Rekursive Funktion für Datenbankabruf

Alles rund um die Programmierung mit Qt
Antworten
Mefisto
Beiträge: 27
Registriert: 6. September 2008 13:37

Rekursive Funktion für Datenbankabruf

Beitrag von Mefisto »

Hallo!

Ich habe hier eine Funktion geschrieben, die rekursiv Werte aus einer Datenbank ausließt, die über zwei zusammenhängende Felder in einer Art Baumstruktur miteinander verknüpft sind. Hier mal ein Beispiel:

Feld 1: iftopic = "", settopic = "Baum"
Feld 2: iftopic = "baum", settopic = "apfel"
Feld 3: iftopic = "apfel", settopic = ""

In diesem Beispiel ergäbe das in der Ausgabe eine ganze einfache Baumansicht (also QTreeWidget) mit einem Parent-Element, einem Child Element und einem diesem erneut untergeordnetem weiterem Child-Element.

Nun rackert sich mein PC aber beim Aufruf dieser Funktion unglaublich ab, ohne das was passiert. Die Maus ruckelt, und es ist manchmal schwer, das Fenster noch geschlossen zu bekommen. Es stimmt also vermutlich etwas mit der Rekursion (sagt man das so?) nicht, da die Datenbank bisher erst etwa 10 Einträge hat und das ganze eigentlich in wenigen Milli-Sekunden ablaufen sollte. Hier mal die Funtkion:

Code: Alles auswählen

QList<QTreeWidgetItem *> recursiveSqlTreeView(QString layer) {
	QList<QTreeWidgetItem *> items;
	QStringList outputrow;
	
	QSqlQuery fetchLayer;
	fetchLayer.exec("SELECT iftopic,settopic,output,regex FROM talking WHERE iftopic='"+layer+"'");
	
	while (fetchLayer.next()) {
		QString iftopic = fetchLayer.value(0).toString(); QString settopic = fetchLayer.value(1).toString();
 		QString output = fetchLayer.value(2).toString(); QString regex = fetchLayer.value(3).toString();
		QStringList outputrow;
		outputrow.append(regex); outputrow.append(output); outputrow.append(settopic); outputrow.append(iftopic);
		
		QTreeWidgetItem *currentitem = new QTreeWidgetItem((QTreeWidget*)0, outputrow);
		
		if(settopic!="") {
			currentitem->addChildren(recursiveSqlTreeView(settopic));
		}
		items.append(currentitem);
	}
	return items;
}
Vielen, vielen Dank schon Mal für Infos udn Tipps :)
Liebe Grüße,

Jonathan
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

Abgesehen von der unnötigen, ersten Instanz "outputrow" ist auf den ersten Blick nichts zu erkennen..
Falls allerdings irgend ein "settopic" in der Datenbanktabelle gleich heisst wie ein anderer "iftopic" hast du genau dein Verhalten... das ist nicht zufälligerweise so?

Zudem fällt es mir schwer zu glauben, dass sich das nicht debuggen lässt.. es wäre doch kein Problem, erstmals nur eine Zeile in der Datenbank zu haben und das ganze mit debugger und/oder qDebug() zu verifizieren... danach zwei Einträge usw...
Mefisto
Beiträge: 27
Registriert: 6. September 2008 13:37

Beitrag von Mefisto »

solarix hat geschrieben: Falls allerdings irgend ein "settopic" in der Datenbanktabelle gleich heisst wie ein anderer "iftopic" hast du genau dein Verhalten
Das ist doch eigentlich das Ziel der Funktion, dass alle Einträge mit dem Wert "Baum" für "iftopic" dem Eintrag mit dem Wert Baum für settopic untergeordnet werden... Aber ich sehe trotzdem nicht, was falsch ist...
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

ich habe mich ungeschickt ausgedrückt: es ist doch möglich, in der Tabelle Zyklen zu konfigurieren... wenn in deinem Beispiel bei Feld 3 settopic wieder gleich "baum" wäre, würde sich der Code ewig durch den Kreis hangeln..

aber es ist schlecht, rekursive Probleme um diese Uhrzeit zu überdenken :wink: evt. übersehe ich auch was..
Mefisto
Beiträge: 27
Registriert: 6. September 2008 13:37

Beitrag von Mefisto »

Hm, vielen Dank, genau daran lag das! Aber das ist jetzt auch irgendwie doof, weil ich eigentlich brauche ich das, was den Crash verursacht... Eine Idee, wie ich das Problem umgehen kann? Weil mir fällt nichts ein :/

Danke nochmal auf jeden Fall für die Hilfe :)
Grüße,
Jonathan
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

Manchmal benötigen rekursive Algorithmen ein "Gedächtnis". In deinem Fall wäre das "alle-besuchten-iftopics". Du musst also eine QStringList als Parameter mitgeben und bei jedem Durchgang "iftopic" hinzufügen.
Die Abbruchbedingung ändert sich dann von

Code: Alles auswählen

 if(settopic!="")
         currentitem->addChildren(recursiveSqlTreeView(settopic));
auf

Code: Alles auswählen

 if(!visitedIftopics.contains(settopic)) // visitedIftopics = QStringList
         currentitem->addChildren(recursiveSqlTreeView(settopic));
Das funktioniert bei deinem Beispiel sowohl am "Ende" eines Astes (der Leerstring "" am Ende ist ja der erste in der Liste eingefügte "besuchte iftopic") als auch bei Zyklen (Abbruch der Rekursion bei "baum" in Feld 3, weil "baum" im zweiten Durchgang zu den "besuchten iftopics" hinzugefügt wurde).

hth,
solariX
Antworten