Menu Close

Diskrete Strukturen (Praktikum 1)

Im Rahmen des ersten Praktikums implementieren wir die Funktionen rankunrank und successor für Gray-Code und entwickeln eine verallgemeinerte Form des Gray-Codes.

Skript-AnfangPraktikum 1 – Seite 1
Skript-EndePraktikum 1 – Seite 2

Algorithmen für den Gray-Code

Entwickeln und beschreiben Sie Algorithmen zur Realisierung rankunrank und successor für Gray-Code \( \Delta_n\), definiert durch:

\( \ \Delta_1 := 0,1 \ \Delta_n := \Delta^R_{n-1}0,\Delta_{n-1}1, n > 1 \)

Nutzen Sie dabei die rekursive Struktur aus. Implementieren Sie die Algorithmen in einer Programmierspache Ihrer Wahl.

Konsolenausgabe des folgenden Quellcodes

rank("000") => 2
rank("001") => 5
rank("010") => 1
rank("011") => 6
rank("100") => 3
rank("101") => 4
rank("110") => 0
rank("111") => 7

unrank(0,3) => 110
unrank(1,3) => 010
unrank(2,3) => 000
unrank(3,3) => 100
unrank(4,3) => 101
unrank(5,3) => 001
unrank(6,3) => 011
unrank(7,3) => 111

succ("110") => 010
succ("010") => 000
succ("000") => 100
succ("100") => 101
succ("101") => 001
succ("001") => 011
succ("011") => 111
succ("111") => 110

Includes und Deklarationen

#include <iostream>
#include <sstream>
#include <vector>
#include <string>
#include <math.h>

using std::cout;
using std::endl;
using std::vector;
using std::string;

int rank(string val);
string unrank(unsigned int i, unsigned int n);
string succ(string val);
vector<string> create_GrayCode2(int n, string q);
template<typename T> string toString(T Val);
unsigned int eval(string val);
char cFlip(char c);
vector<string> reverse(vector<string> v);

Main()

int main() {

	cout << "rank(\"000\") => " << rank("000") << endl;
	cout << "rank(\"001\") => " << rank("001") << endl;
	cout << "rank(\"010\") => " << rank("010") << endl;
	cout << "rank(\"011\") => " << rank("011") << endl;
	cout << "rank(\"100\") => " << rank("100") << endl;
	cout << "rank(\"101\") => " << rank("101") << endl;
	cout << "rank(\"110\") => " << rank("110") << endl;
	cout << "rank(\"111\") => " << rank("111") << endl;
	cout << endl;

	cout << "unrank(0,3) => " << unrank(0, 3) << endl;
	cout << "unrank(1,3) => " << unrank(1, 3) << endl;
	cout << "unrank(2,3) => " << unrank(2, 3) << endl;
	cout << "unrank(3,3) => " << unrank(3, 3) << endl;
	cout << "unrank(4,3) => " << unrank(4, 3) << endl;
	cout << "unrank(5,3) => " << unrank(5, 3) << endl;
	cout << "unrank(6,3) => " << unrank(6, 3) << endl;
	cout << "unrank(7,3) => " << unrank(7, 3) << endl;
	cout << endl;

	cout << "succ(\"110\") => " << succ("110") << endl;
	cout << "succ(\"010\") => " << succ("010") << endl;
	cout << "succ(\"000\") => " << succ("000") << endl;
	cout << "succ(\"100\") => " << succ("100") << endl;
	cout << "succ(\"101\") => " << succ("101") << endl;
	cout << "succ(\"001\") => " << succ("001") << endl;
	cout << "succ(\"011\") => " << succ("011") << endl;
	cout << "succ(\"111\") => " << succ("111") << endl;
	cout << endl;

	return 0;
}	// main

Rank

int rank(string val) {
	/* Rank-Algorithmus fuer den Gray-Code */

	int r = 0;
	// Abbruchbedingung
	if (val.length() == 1) {
		//cout << "Abbruchbedingung erfuellt!" << endl;
		if (val[val.length() - 1] == '1')
			return 1;
		else
			return 0;
	}

	if (val[val.length() - 1] == '0') {
		// letztes Zeichen entfernen
		string tmp = val.substr(0, val.size() - 1);
		// neues letztes Zeichen drehen
		if (tmp[tmp.length() - 1] == '0')
			tmp[tmp.length() - 1] = '1';
		else
			tmp[tmp.length() - 1] = '0';

		//cout << "Rekursion: rank(" << tmp << ")" << endl;
		return r + rank(tmp);
	} else {
		// letztes Zeichen ist eine 1
		return r + pow(2, val.size()) / 2 + rank(val.substr(0, val.size() - 1));
	}
}	// rank

Unrank

string unrank(unsigned int i, unsigned int n) {
	/* Unrank-Algorithmus fuer den Gray-Code */

	string s = "";

	// Abbruchbedingung
	if (i >= pow(2, n))
		return "Keine Berechnung moeglich.";

	if (n == 0)
		return "";

	// Wenn i < Anzahl aller Teilmengen / 2 (2**n / 2)
	// 1. i befindet sich in der gespiegelten Haelfte
	// 2. Das letzte Zeichen ist eine "0"
	if (i < pow(2, n) / 2) {
		// Bestimme naechste Stelle
		s = unrank(i, n - 1);
		// Da wir uns in der gespiegelten Haelfte befinden
		// -> drehe das Bit der naechsten Stelle (also vor der "0") um
		s[s.size() - 1] = cFlip(s[s.size() - 1]);
		return s + "0";
	} else {
		// Wenn i >= Anzahl aller Teilmengen / 2 (2**n / 2)
		// 1. i befindet sich in der nicht gespiegelten Haelfte
		// 2. Das letzte Zeichen ist eine "1"
		// -> Subtrahiere den Offset (2** n / 2( von i und bestimme naechste Stelle
		return unrank(i - (pow(2, n) / 2), n - 1) + "1";
	}
}		// unrank

Successor

string succ(string val) {
	/* Successor-Implementierung fuer den Gray-Code */

	if (eval(val) % 2 == 1) { // Anzahl 0 ungerade
		//cout << "Anzahl ungerade" << endl;
		val[0] = cFlip(val[0]);
	} else { // Anzahl 0 gerade
			 // Finde erste 0 von links
			 // oder letzte von rechts
		std::size_t found = val.find_first_of("0");
		if (found != std::string::npos)
			val[found + 1] = cFlip(val[found + 1]);
		else
			val[val.size() - 1] = cFlip(val.size() - 1);
	}
	return val;
}			 // succ

Hilfsfunktionen

template<typename T>
string toString(T Val) {
    std::stringstream ss;
    ss << Val;
    return ss.str();
}

unsigned int eval(string val) {
    /* Hilfsfunktion Bestimmung der Anzahl aller Nullen eines Zeichenkette */
 
    // Abbruchbedingung
    if (val.size() == 0)
        return 0;
    if (val[val.size() - 1] == '0')
        return eval(val.substr(0, val.size() - 1)) + 1;
    else
        return eval(val.substr(0, val.size() - 1)) + 0;
}       // eval
 
char cFlip(char c) {
    /* Hilfsfunktion: Invertierung eines 'Bits' */
 
    if (c == '0')
        return '1';
    else
        return '0';
}       // cFlip
 
vector<string> reverse(vector<string> v) {
    /* Hilfsfunktion: Invertierung von Vektoren */
 
    vector<string> vTmp;
    for (unsigned int i = 0; i < v.size(); i++)
        vTmp.insert(vTmp.begin(), v[i]);
    return vTmp;
}       // reverse

Verallgemeinerung des Gray-Codes

Entwickeln und implementieren Sie einen Algorithmus zum Erzeugen aller Vektoren der Länge n mit Vektoreinträgen aus {0, 1,…, q – 1}, wobei sich zwei aufeinanderfolgende Vektoren an exakt einer Stelle unterscheiden sollen. Für q = 2 entspricht dies einem Gray-Code. Gehen Sie rekursiv wie für den Fall q = 2 vor.

Konsolenausgabe des folgenden Quellcodes

create_GrayCode2(n=3 q='01') => 110 010 000 100 101 001 011 111 

create_GrayCode2(n=3 q='012') => 020 120 220 210 110 010 000 100 200 201 101 001 011 111 211 221 121 021 022 122 222 212 112 012 002 102 202 

create_GrayCode2(n=4 q='012') => 2020 1020 0020 0120 1120 2120 2220 1220 0220 0210 1210 2210 2110 1110 0110 0010 1010 2010 2000 1000 0000 0100 1100 2100 2200 1200 0200 0201 1201 2201 2101 1101 0101 0001 1001 2001 2011 1011 0011 0111 1111 2111 2211 1211 0211 0221 1221 2221 2121 1121 0121 0021 1021 2021 2022 1022 0022 0122 1122 2122 2222 1222 0222 0212 1212 2212 2112 1112 0112 0012 1012 2012 2002 1002 0002 0102 1102 2102 2202 1202 0202 

create_GrayCode2(n=3 q='AB') => BBA ABA AAA BAA BAB AAB ABB BBB 

Main()

int main() {

	vector<string> vOut;
	vOut = create_GrayCode2(3, "01");
	cout << "create_GrayCode2(n=3 q='01') => ";
	for (unsigned int i = 0; i < vOut.size(); i++) {
		cout << vOut.at(i) << " ";
	}
	cout << endl << endl;

	vOut = create_GrayCode2(3, "012");
	cout << "create_GrayCode2(n=3 q='012') => ";
	for (unsigned int i = 0; i < vOut.size(); i++) {
		cout << vOut.at(i) << " ";
	}
	cout << endl << endl;

	vOut = create_GrayCode2(4, "012");
	cout << "create_GrayCode2(n=4 q='012') => ";
	for (unsigned int i = 0; i < vOut.size(); i++) {
		cout << vOut.at(i) << " ";
	}
	cout << endl << endl;

	vOut = create_GrayCode2(3, "AB");
	cout << "create_GrayCode2(n=3 q='AB') => ";
	for (unsigned int i = 0; i < vOut.size(); i++) {
		cout << vOut.at(i) << " ";
	}
	cout << endl << endl;

	return 0;
}	// main

Gray-Code

vector<string> create_GrayCode2(int n, string q) {
	/* Verallgemeinerung des Gray-Code Algorithmus
	 * -> q kann beliebige Zeichen enthalten
	 */

	vector<string> v;

	// Abbruchbedingung
	if (n == 0) { // Leere Menge
		v.push_back("");
		return v;
	}

	if (n == 1) { // Minimum
		for (unsigned int i = 0; i < q.size(); i++)
			v.push_back(toString(q.at(i)));
		return v;
	}

	// Rekursion: Erzeuge "unteren" Vektor (n - 1)
	// -> Hinweis: Rekursion endet bei n=1!
	// -> Fuer q = 3 waere vNew = {0, 1, 2}
	vector<string> vNew = create_GrayCode2(n - 1, q);

	// Baue Vektor n fuer jedes Zeichen in q zusammen
	for (unsigned int i = 0; i < q.size(); i++) {
		vector<string> vTmp;
		// Gray-Algorithmus beginnt immer mit invertiertem Vektor
		// -> Der dritte, fuenfte etc. Vektor muss wieder invertiert sein (q=2,4,...)
		// -> Alle restlos durch zwei teilbaren 'Positionen' sind zu invertieren!
		if (i % 2 == 0)
			vTmp = reverse(vNew);
		else
			vTmp = vNew;

		// Zeichen anhaengen
		for (unsigned int j = 0; j < vTmp.size(); j++)
			vTmp.at(j) = vTmp.at(j) + toString(q.at(i));

		// In den Hauptvektor kopieren
		v.insert(v.end(), vTmp.begin(), vTmp.end());

	}
	// Vektor fuer das aktuelle n zurueckgeben
	return v;
}		// create_GrayCode2

Schreiben Sie einen Kommentar

Ihre E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahren Sie, wie Ihre Kommentardaten verarbeitet werden.

Index