Seite 1 von 1

Rekursive Funktion für Datenbankabruf

Verfasst: 17. März 2009 22:52
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

Verfasst: 17. März 2009 23:24
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...

Verfasst: 17. März 2009 23:27
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...

Verfasst: 17. März 2009 23:47
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..

Verfasst: 18. März 2009 00:09
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

Verfasst: 18. März 2009 09:09
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