Guten Morgen,
ich habe eine kleines Problem bei dem ich nicht weiterkomme. Es geht
darum eine gewissen Datenmenge (Größe nicht bekannt) zu sortieren. Die
Daten haben folgende Struktur:
1
1 -> 0
2
2 -> 17563
3
3 -> 3059
4
4 -> 300
5
3 -> 127
6
4 -> 168
7
3 -> 248
8
...
Die Zielstruktur soll sein:
1
1 -> 0,
2
2 -> 17563,
3
3 -> 3059, 127, 248
4
4 -> 300, 168
Die Beispiele die ich bisher gefunden habe waren für C++ und nicht für
C. Kann mir jemand einenn Tip geben?`
Gruß
Die Suchworte sind Hashtables, verkettete Listen, dynamische Arrays.
Gibts in C nicht als Standard, muss man selber programmieren, in C# C++
oder Java ist sowas schon mit dabei.
Mir erschliesst sich nicht ganz, wie die Zielstruktur zustande kommt.
Entweder bin ich zu blöd oder ein paar nähere Erläuterungen wären gut.
Grüsse,
R.
Udo Schmitt schrieb:> Gibts in C nicht als Standard, muss man selber programmieren
Deswegen frage ich ja. Die Beispiele die ich gefunden haben bezogen
sich immer auf C++ mit "new" und "free".
Rene schrieb:> Mir erschliesst sich nicht ganz, wie die Zielstruktur zustande kommt.
Es geht um eine Clusterung der Daten in ersten Spalte. Nach dem Motto
1
Durchlaufe alle Zeilen der Daten
2
Wenn Wert in erster Spalte nicht vorhanden: lege neues Array an
3
wenn vorhanden: hänge den Wert an das bestehende Array an
Ich habe mal folgendes "übersetzt", ist aber nur der erste Schritt. Das
Problem ist, dass das Programm nach Ausgabe der Zahl abstürzt. Ich nehme
mal an, dass liegt an dem free in der Schleife?
1
#include<stdio.h>
2
#include<stdlib.h>
3
intmain(){
4
intFirstDim=4;
5
intSecDim=5;
6
inti,j;
7
8
// 1. Schritt: Dynamische Array von Zeigern anlegen:
Rene schrieb:> Das wird so wohl kaum klappen. Du allokierst ein array von 5 Bytes. Ein> Zeiger wird aber, je nach System, sicher 2 - 4 Bytes brauchen.>> Grüsse,> R.
Wenn du mit alloc Speicher für Arrays allozieren willst, brauchst du die
Anzahl der Elemente und die Größe des einzelnen Elements.
Die beiden musst du multiplizieren.
Schau dir sizeof() an.
Rene schrieb:> Mach ein sizeof(int*), das ist schöner.
Nein richtiger! Es gibt durchaus Systeme auf denen sizeof(int) und
sizeof(int *) unterschiedliche Größe bringen.
Ich sage mal AS400 :-)
Rene schrieb:> Das stimmt. Aber ich vermute mal nicht, das er solche Übungen auf einem> AS400 macht :-).
Ist aber eigentlich ziemlich egal.
Da malloc die zu allokierende Größe in Bytes haben will, lautet die
einfache Formel für die zu allokierende Größe
malloc( Anzahl_Elemente * sizeof( Einzelelement ) )
// 1. Schritt: Dynamische Array von Zeigern anlegen:
7
int**p2DimArr=malloc(FirstDim);
8
9
// 2. Schritt: An jeden Zeiger ein Array hängen
10
for(i=0;i<FirstDim;i++){
11
p2DimArr[i]=malloc(SecDim);
12
}
wozu dann überhaupt dynamisch allokieren :-)
Der Knackpunkt in deinem Programm ist ja, dass sich die Allokierungen im
Programmlauf vergrößern müssen, wenn neue Daten dazukommen. realloc()
ist dein Freund.
* Der 'Key' in deinen Daten (also die erste Zahl). Ist die immer
beginnend bei 1 und aufsteigend? Oder könnte deine Zuordnung zb auch so
aussehen:
98 -> 178
5 -> 234
23 -> 45
98 -> 675
mit dem Ergebnis
98 178, 675
5 234
23 45
wenn ja, dann wirst du dir auch die erste Zahl irgendwo merken müssen.
Momentan tust du das nicht.
Weiters ist die Fragestellung die, ob das Ergebnis dieser letzten Daten
so aussehen soll wie gepostet, oder ob es nicht eher so aussehen soll
5 234
23 45
98 178, 675
(Also auch noch sortiert nach dem Key. Etwas was sich in deinem
ursprünglichen Fall, durch die 'Vorsortierung' der Eingangsdaten
automatisch ergibt, nicht notwendigerweise aber im allgemeinen Fall
vorhanden ist. Ich ignorier den Fall mal, denn in diesem Fall würde sich
eine komplett andere Vorgangsweise sowohl algorithmisch als auch Form
der Datenstruktur aufdrängen)
Da empfehle ich doch glatt für die erste 'Dimension' des 2D-Arrays keine
einfachen Pointer, sondern eine Struktur
* und eine Aufteilung in Funktionen wär auch nicht schlecht. Zumindest
eine Funktion zum Finden eines 'key' in den Daten braucht man praktisch
immer. Und dann gibt es 2 Fälle:
+ entweder der Key wurde gefunden, dann wird an dessen 'data' ein neues
Element angehängt und der Wert eingetragen
+ oder es gibt ihn noch nicht, dann wird das DataSet um 1 Eintrag
erweitert, der key eingetragen und der Wert angehängt.
den letzten Punkt, das Anhängen des Wertes an ein struct DataSet
erledigt am besten wieder eine Funktion, den dieser Vorgang wird in
beiden Fällen gebraucht.
Eine ganz brauchbare Strategie ist es, sich erst mal in Form von
Kommentaren umgangssprachlich klar zu machen, wie denn der ganze Vorgang
laufen muss ....
Du schreibst jetzt noch die Funktionen
FindKey()
AddValue()
PrintDataSet()
FreeDataSet()
kümmerst dich noch um Fehlerbehandlung und fertig ist die Laube.
(
und den ganzen Programmblock um den Nein-Zweig solltes du in eine eigene
Funktion 'AddKey' auslagern ...
// wenn ja, dann einfach den value an diesen Eintrag anhängen
8
if(existingKey!=NULL)
9
AddValue(existingKey,value);
10
11
// wenn nein, dann einen neuen Eintrag erzeugen, und dort den
12
// Wert value anhängen
13
else{
14
existingKey=AddKey(data,key);
15
AddValue(existingKey,value);
16
}
17
}
dann bemerkt man auch, dass AddValue in beiden Fällen jeweils am Ende
steht und daher zusammengefasst werden kann, wodurch sich InsertPair
vereinfacht zu
// wenn es für diesen key noch keinen Eintrag gibt, dann
8
// erzeuge einen neuen dafür.
9
if(existingKey==NULL)
10
existingKey=AddKey(data,key);
11
12
// und den zugehörigen Wert eintragen
13
AddValue(existingKey,value);
14
}
und das ist ja nun wirklich einfach genug, damit man sich laut
Augenschein davon überzeugen kann, dass diese 'Logik' grundsätzlich
(d.h. ohne die Behandlung von Fehlern) richtig ist. Und in dem Fall kann
man dann auch die Kommentare weglassen, weil meiner Meinung nach der
Programmtext recht eindeutig beschreibt, was hier passiert. Mit gut
gewählten Funktions-, Member- und Variablennamen erzählt der Code selber
die Geschichte, wie er funktioniert und was er eigentlich macht.
)
Und du siehst schon:
mit einem 2D-Array hat das Ganze eigentlich nur noch im weitesten Sinne
irgendwas zu tun. Löse dich von der Vorstellung, dass alles einfach nur
n-dimensionale Arrays sind. Dieser Gedanke hindert dich mehr als er dir
nützt. Mach dir statt dessen lieber Gedanken um einen vernünftigen
Aufbau der Datenstruktur. Ein paar Zeichnungen und Skizzen dazu sind
viel hilfreicher als nach "C 2D Array" zu googeln und nicht weiter zu
kommen. Mal dir auf, wie deine Datenorganisation aussehen soll,
übersetze die Knoten in vernünftige Strukturen, so dass an jedem Knoten
(und damit in den Strukturen) die jeweils benötigten Member enthalten
sind und dann kommst du auch weiter. Ihr fangt immer viel zu schnell an
Code zu schreiben, ohne euch über das was zu tun ist, bzw. den Aufbau
der Datenstrukturen im klaren zu sein.
Karl Heinz Buchegger schrieb:> Wobei.> Wenn du es so machst wozu dann überhaupt dynamisch allokieren :-)
Ich esse den Elefanten Stück für Stück... ;-)
> Der Knackpunkt in deinem Programm ist ja, dass sich die Allokierungen im> Programmlauf vergrößern müssen, wenn neue Daten dazukommen. realloc()> ist dein Freund.
Richtig. Mein Gedanke war jetzt: baue ich das in irgendeiner Form in
eine lineare Liste ein oder gibt es die Möglichkeit das "einfacher" zu
lösen.
> * Der 'Key' in deinen Daten (also die erste Zahl). Ist die immer> beginnend bei 1 und aufsteigend?
Die originale Datenbasis ist bezüglich der Reihenfolge des "Key" völlig
frei! Gleiches gilt für die Länge (Anzahl der Zeilen) und Anzahl des
Auftretens eines bestimmten Key.
> Weiters ist die Fragestellung die, ob das Ergebnis dieser letzten Daten> so aussehen soll wie gepostet, oder ob es nicht eher so aussehen soll
Das ist prinzipiell egal. Ich muss den Key natürlich wiederfinden
können..
Aus deinen ausführlichen (danke dafür!) Erläuterungen schließe ich: ich
werde das Ganze in einer Liste organisieren.
Gruß
Dennis S. schrieb:> Ich esse den Elefanten Stück für Stück... ;-)
Wobei du angenommen hast, dass du einen Elefanten vor dir hast. In
Wirklichkeit hast du es aber mit gar keinem Elefanten zu tun. Daher
versteifst du dich auf das falsche Besteck.
> Richtig. Mein Gedanke war jetzt: baue ich das in irgendeiner Form in> eine lineare Liste ein oder gibt es die Möglichkeit das "einfacher" zu> lösen.
Machs erst mal mit größer werdenden Arrays :-)
Danach kannst du die Einzelteile immer noch gegen richtige verkettete
lineare Listen austauschen. Mit einer ordentlichen Code-Organisation ist
das überhaupt kein Problem (zb. verändert das die Funktion InsertPair
nicht im geringsten). Man kann dann sogar in Schritten vorgehen: erst
mal die key-values-Knoten auf eine Liste umstellen und dann die values
selber auf eine Liste umstellen.
Aber bei deinem Kenntnissstand solltest du erst mal gehen lernen, ehe du
dich zum Marathon anmeldest.
Danke für deinen Rat. Aber die Liste habe ich bereits fertig
programmiert und ausgiebig getestet.. ;-) Ich hatte einfach das Gefühl,
dass das überdimensioniert ist wenn man mehr oder weniger nur ein paar
Werte in einer Matrix (das ist es ja im Prinzip) anhängen will.
Gruß
Rene schrieb:> Aber ich vermute mal nicht, das er solche Übungen auf einem> AS400 macht :-).
Dann nehmen wir doch einfach was gebräuchlicheres, wie z.B. einen PC.
Bei den gängigen 64-Bit-Betriebssystemen ist dort ein Zeiger doppelt so
groß wie ein int.
Rolf Magnus schrieb:> Rene schrieb:>> Aber ich vermute mal nicht, das er solche Übungen auf einem>> AS400 macht :-).>> Dann nehmen wir doch einfach was gebräuchlicheres, wie z.B. einen PC.> Bei den gängigen 64-Bit-Betriebssystemen ist dort ein Zeiger doppelt so> groß wie ein int.
Mann Jungs, was hängt ihr euch jetzt an dem auf. Ihr sucht spezial Fälle
raus. Selbst heute kompiliert kaum einer mit 64Bit. Sicher nicht jemand
der solche Fragen stellt.
Ich bin Schweizer und wollte lediglich den diplomatischen Hinweis geben,
es wäre besser mit (int *).
Man muss da echt kein Fass über "schöner" oder "richtiger" aufmachen.
Ich entwickle genug lange in C/C++ auf verschiedenen Systemen um Code
portabel zu erstellen. Das war allerdings nicht die Frage (ich darf auf
den sehr guten Artikel von Cyberlord hinweisen).
Auch kenne ich den Unterschied zwischen Adressbus und Datenbus und deren
Breite.
Grüsse,
R.
Rene H. schrieb:> Ich bin Schweizer und wollte lediglich den diplomatischen Hinweis geben,> es wäre besser mit (int *).
Du darfst ruhig an dieser Stelle die Diplomatie beiseite lassen.
Sei T irgendein Datentyp, dann kann man seinen Allerwertesten darauf
verwetten, dass bei einer Allokierung, die nicht so aussieht
(sizeof-mässig, mit der Ausnahme von T == char)
T * pVar = malloc( Anzahl * sizeof( T ) );
etwas im Argen liegt.
Bei ihm ist T gleich int*, also muss der int* auch im sizeof vorkommen.
Ganz einfache Regel. Da ist Diplomatie fehl am Platze.
Karl Heinz Buchegger schrieb:> Rene H. schrieb:>>>> Ich bin Schweizer und wollte lediglich den diplomatischen Hinweis geben,>> es wäre besser mit (int *).>> Du darfst ruhig an dieser Stelle die Diplomatie beiseite lassen.> Sei T irgendein Datentyp, dann kann man seinen Allerwertesten darauf> verwetten, dass bei einer Allokierung, die nicht so aussieht> (sizeof-mässig, mit der Ausnahme von T == char)>> T * pVar = malloc( Anzahl * sizeof( T ) );>> etwas im Argen liegt.>> Bei ihm ist T gleich int*, also muss der int* auch im sizeof vorkommen.> Ganz einfache Regel. Da ist Diplomatie fehl am Platze.
<offtopic> Das ist schon klar. Das wird der Grund sein weshalb sich mein
"lecker Kölsch Mädschen" sich dauernd mit mir zankt. </offtopic>
Ich bin auf 7X24 Realtime Systeme spezialisiert (Unix) und bin mir
dessen "Kleinigkeiten" sehr wohl bewusst.
Nun gut, ich wollte niemanden vor den Kopf stossen, sondern lediglich
darauf Hinweisen.
Grüsse,
R.
Rene H. schrieb:> Ich bin auf 7X24 Realtime Systeme spezialisiert (Unix) und bin mir> dessen "Kleinigkeiten" sehr wohl bewusst.
Darum gehts nicht.
> Nun gut, ich wollte niemanden vor den Kopf stossen
darum schon eher.
Das war ein ganz klarer Fehler von Dennis. Mit 'Diplomatie' hast du es
zu einem Schönheitsfehler gewandelt. Das war es aber nicht. Es war
schlicht und ergreifend falsch. Das darf man ruhig auch so sagen,
deswegen ist keiner böse.
Karl Heinz Buchegger schrieb:> Das war ein ganz klarer Fehler von Dennis.
Und ein Vermeidbarer noch dazu, schließlich ist mir die "Regel" mit
sizeof natürlich bekannt.
> Das darf man ruhig auch so sagen, deswegen ist keiner böse.
Richtig!
Gruß Dennis