Mindmap-Galerie Datenstruktur lineare Tabelle
Datenstruktur Kapitel 2 Lineare Tabelle Mind Map: 1. Die Definition und Grundoperationen einer linearen Tabelle Eine lineare Tabelle ist eine endliche Folge von n Datenelementen mit demselben Datentyp. , 2. Sequentielle Darstellung linearer Listen (sequentielle Listen), 3. Verkettete Darstellung linearer Listen usw.
Bearbeitet um 2022-03-31 18:41:13Welche Preismethoden gibt es für Projektunteraufträge im Rahmen des EPC-Generalvertragsmodells? EPC (Engineering, Procurement, Construction) bedeutet, dass der Generalunternehmer für den gesamten Prozess der Planung, Beschaffung, Konstruktion und Installation des Projekts verantwortlich ist und für die Testbetriebsdienste verantwortlich ist.
Die Wissenspunkte, die Java-Ingenieure in jeder Phase beherrschen müssen, werden ausführlich vorgestellt und das Wissen ist umfassend. Ich hoffe, es kann für alle hilfreich sein.
Das Software-Anforderungs-Engineering ist ein Schlüsselkapitel für Systemanalytiker. Zu den Kapiteln „Anforderungserhebung“ und „Anforderungsanalyse“ gehören häufig Veröffentlichungen.
Welche Preismethoden gibt es für Projektunteraufträge im Rahmen des EPC-Generalvertragsmodells? EPC (Engineering, Procurement, Construction) bedeutet, dass der Generalunternehmer für den gesamten Prozess der Planung, Beschaffung, Konstruktion und Installation des Projekts verantwortlich ist und für die Testbetriebsdienste verantwortlich ist.
Die Wissenspunkte, die Java-Ingenieure in jeder Phase beherrschen müssen, werden ausführlich vorgestellt und das Wissen ist umfassend. Ich hoffe, es kann für alle hilfreich sein.
Das Software-Anforderungs-Engineering ist ein Schlüsselkapitel für Systemanalytiker. Zu den Kapiteln „Anforderungserhebung“ und „Anforderungsanalyse“ gehören häufig Veröffentlichungen.
Kapitel 2 Lineare Tabelle
1. Definition und Grundoperationen linearer Tabellen
Definition einer linearen Tabelle
Eine lineare Tabelle ist eine endliche Folge von n Datenelementen desselben Datentyps.
Konzept: Header-Element, Tail-Element, direkter Vorgänger, direkter Nachfolger.
Grundlegende Operationen linearer Tabellen
Das Einrichten von InitList(&L) besteht darin, DestroyList(&L) zu initialisieren und zu zerstören. Fügen Sie ListInsert(&L,i,e) zum Einfügen hinzu DeleteListDelete(&L,i,e) CheckLocateElem(L,e),GetElem(L,e) Länge (L) Tabellenlänge, PrintList(L)-Ausgabe, Leer (leeres Urteil)
2. Sequentielle Darstellung linearer Tabellen (sequentielle Tabellen)
Definition der Sequenztabelle
Implementieren Sie lineare Tabellen mithilfe sequentieller Speicherung. Sequentielle Lagerung: Lagern Sie logisch benachbarte Elemente in Speichereinheiten, die auch physisch benachbart sind. Die Beziehung spiegelt sich in der Nachbarschaftsbeziehung der Speichereinheiten wider.
Implementierung einer Sequenztabelle
statische Zuordnung
// Die statische Zuweisung definiert die Sequenztabelle. Der Speicherplatz ist statisch und die Größe ist von Anfang an festgelegt. #define MaxSize 10//Definieren Sie die maximale Länge typedef struct{ ElemType data[MaxSize]; //Statisches „Array“ zum Speichern von Datenelementen verwenden int length; //Aktuelle Länge der Sequenztabelle }SqList; //Typdefinition der Sequenzliste (statische Zuordnungsmethode) ElemType bezieht sich auf den von Ihnen definierten Datentyp, z. B. int, double //Initialisierungssequenztabelle #include<stdio.h> #define MaxSize10 typedef struct{ int data[MaxSize]; int Länge; }SqList; void InitList(SqList &L){ for(int i=0;i<MaxSize;i) L.data[i]=0; //Alle Datenelemente auf Standardanfangswerte setzen L.length=0; //Setzen Sie die Anfangslänge der Sequenztabelle auf 0 } int main(){ SqList L; //Eine Sequenzliste deklarieren InitList(L): //Initialisierungssequenzliste ... 0 zurückgeben; } // Dynamische Zuordnungs-Implementierungssequenztabelle, die Größe kann geändert werden #include<stiod.h> #define InitSize 10 //Standardmäßige maximale Länge typedef struct{ int *data; //Zeiger, der das dynamisch zugewiesene Array anzeigt int MaxSize; //Maximale Kapazität der Sequenztabelle int length; //Aktuelle Länge der Sequenztabelle }SeqList; //Definition der Sequenzliste int main(){ SeqList L; //Eine Sequenzliste deklarieren InitList(L): //Mehrere Elemente zufällig in die Netzwerksequenztabelle einfügen Erhöhen Sie die Größe (L, 5); 0 zurückgeben; } void InitList(SeqList &L){ //Verwenden Sie die malloc-Funktion, um einen kontinuierlichen Speicherplatz zu beantragen L.data(int *)malloc(InitSize*sizeof(int)); L.length=0; L.MaxSize=InitSize; } //Erhöhen Sie die Länge des dynamischen Arrays void raiseSize(SeqList &L,int len){ int *p=L.data; L.data(int *)malloc((L.MaxSize len)*sizeof(int)): for(int i=0;i<L.length;i ){ L.data[i]=p[i]; //Daten in neuen Bereich kopieren } L.MaxSize=L.MaxSize len; //Die maximale Länge der Sequenztabelle erhöht sich um len free(p); //Den ursprünglichen Speicherplatz freigeben }
dynamische Zuordnung
L.data=(ElemType *)malloc(sizeof ElemType *InitSize) Die malloc-Funktion gibt einen Zeiger zurück, der in einen Zeiger auf den von Ihnen definierten Datenelementtyp umgewandelt werden muss.
Merkmale von Sequenztabellen: ① Direktzugriff ②Hohe Speicherdichte ③Es ist unpraktisch, die Kapazität zu erweitern ④ Einfüge- und Löschvorgänge sind umständlich und erfordern das Verschieben einer großen Anzahl von Elementen
Einfügen und Löschen einer Sequenztabelle
Einfügen in die Sequenztabelle
ListInsert(&L,I,e) fügt das angegebene Element e an der i-ten Position ein
// Sequentielles Einfügen von Tabellenelementen #define MaxSize 10 typedef struct{ ElemType-Daten[MaxSize]; int Länge; }SqList; void ListInsert(SqList &L,int I,int e){ for(int j=L.length;j>I;j--){ //Das i-te Element und die nachfolgenden Elemente nach hinten verschieben L.data[j]=L.data[j-1]; } L.data[i-1]=e; //Setze e an der i-ten Position L.length; //Länge 1 } int main(){ SqList L; InitList(L): // Wird hier weggelassen, Sie können eine Reihe von Elementen einfügen ListInsert(L,3,3); 0 zurückgeben; } //Um zu vermeiden, dass Elemente ohne Rückmeldung eingefügt werden, beispielsweise wenn der Speicher voll ist, muss die Funktion Einfügen so geändert werden, dass sie einen Rückgabewert hat. bool ListInsert(SqList &L,int I,int e){ if(i<1 || i>L.length 1) falsch zurückgeben; if(L.length>=MaxSize) falsch zurückgeben; for(int j=L.length;j>i;j--) L.data[j]=L.data[j-1]; L.data[i-1]=e; L.Länge; falsch zurückgeben; }
Zeitliche Komplexität der Einfügung: bestes O(1), schlechtestes O(n), durchschnittliches O(n)
Löschen der Sequenztabelle
ListDelete(SqList &L,int i,int &e) löscht das Element an Position i in Tabelle L und gibt den Wert des Elements zurück
//Sequenztabelle löschen bool ListDelete(SqList &L,int i,int &e){ if(i<1 || i>L.length 1) //Bestimmen Sie, ob der Bereich von i gültig ist falsch zurückgeben; e=L.data[i-1]; for(int j=1;j<L.length;j) L.data[j-1]=L.data[j]; L.Länge--; return true; } int main(){ SqList L; InitList(L); int e=-1; if(ListDelete(L,3,e)) printf("Das dritte Element löschen, der Wert des gelöschten Elements ist =%d/n",e); anders pprintf("Die Bitreihenfolge i ist illegal, das Löschen ist fehlgeschlagen "); 0 zurückgeben; }
Zeitliche Komplexität der Löschung: O(1) im besten Fall, O(n) im schlechtesten Fall, O(n) im Durchschnitt
Suche nach Sequenztabellen
Bitweise Suche
GetElem(L,i) ruft den Wert des Elements an der i-ten Position in Tabelle L ab
//Suche nach Bit //Statische Zuordnung #MaxSize definieren typedef struct{ ElemType data[MaxSize]; //Statisches „Array“ zum Speichern von Datenelementen verwenden int length; //Aktuelle Länge der Sequenztabelle }SqList; //Typdefinition der Sequenzliste (statische Zuordnungsmethode) ElemType GetElem(SqList L,int i){ return L.data[i-1]; //Rufen Sie die Funktion GetElem() auf, um den Wert des i-ten Elements zurückzugeben } //Dynamische Zuordnung #defineInitSize typedef struct{ ElemType *data; int MaxSize; int Länge; }SeqList; ElemType GetElem(SeqList L,int i){ return L.data[i-1]; }
Nach Wert suchen
LocateElem(L,e) findet das Element mit dem angegebenen Schlüsselwortwert in Tabelle L
//Nach Wert suchen #defineInitSize 10 typedef struct{ ElemType *data; int MaxSize; int Länge; }SeqList; //Suchen Sie das Element, dessen erster Elementwert gleich e ist, in der Sequenzliste L und geben Sie seine Bitreihenfolge zurück int LocateElem(SeqList L,ElemType e){ for(int i=0;i<L.length,i) if(int i=0;o<L.length;i) return i 1; //Der Wert des mit i markierten Elements im Array ist gleich e und seine Bitreihenfolge wird mit i 1 zurückgegeben return 0; //Schleife verlassen, was darauf hinweist, dass die Suche fehlgeschlagen ist }
Zeitkomplexität: bestes O(1), schlechtestes O(n), durchschnittliches O(n)
Vergleich der Strukturtypen
3. Kettendarstellung einer linearen Tabelle
Einzelliste
Definition einer einfach verknüpften Liste
Zusätzlich zum Speichern von Datenelementen speichert jeder Knoten auch einen Zeiger auf den nächsten Knoten.
Codedarstellung einer einzelnen verknüpften Liste
struct LNode{ ElemType data; //Definieren Sie den Knotentyp einer einzelnen verknüpften Liste struct LNode *next;//Jeder Knoten speichert ein Datenelement } struct LNode *p=(struct LNode *)malloc(sizeof(struct LNode)); //Jedes Mal, wenn ein neuer Knoten hinzugefügt wird, beantragen Sie einen Knotenplatz im Speicher und verwenden Sie den Zeiger p, um auf diesen Knoten zu zeigen Sie können auch typedef struct LNode LNode; anstelle von LNode *p=(LNode *)maloc(sizeof(LNode)); verwenden. In diesem Fall benötigen Sie struct LNode nicht, um Knoten hinzuzufügen.
//Lehrbuch, definiere eine einfach verknüpfte Liste typedef struct LNode{} //Definieren Sie den Knotentyp einer einzelnen verknüpften Liste ElemType-Daten; //Datenfeld struct LNode *next; //Zeigerfeld LNode,*LinkList; //LNode wird umbenannt, *LinkList ist der Zeiger auf diesen Knoten Verwenden Sie LNode *, um hervorzuheben, dass es sich um einen Knoten handelt Verwenden Sie LinkList, um hervorzuheben, dass es sich um eine einfach verknüpfte Liste handelt
Zwei Implementierungen
Führender Knoten
//Einfach verknüpfte Liste mit Kopfknoten typedef struct LNode{ ElemType-Daten; strut LNode *next; }LNode,*LinkLst; //Eine leere einfach verknüpfte Liste initialisieren bool InitList(LinkList &L){ L=NULL; //Tabelle leeren, schmutzige Daten platzieren return true; } void test(){ LinkList L; //Deklarieren Sie einen Zeiger auf eine einfach verknüpfte Liste //Eine leere Tabelle initialisieren InitList(L); //....Folgender Code } //Bestimmen Sie, ob die einfach verknüpfte Liste leer ist bool Empty(LinkList L){ return (L=NULL); }
Kein führender Knoten
//Einfach verknüpfte Liste ohne Kopfknoten typedef struct LNode{ ElemType-Daten; struct LNode *next; }LNode,*LinkList; //Eine einfach verknüpfte Liste mit Header-Knoten initialisieren bool InitList(LinkList &L){ L=(LNode *)malloc(sizeof(LNode));//Weisen Sie einen Hauptknoten zu if(L==NULL) falsch zurückgeben; L->next=NULL; return true; } void test(){ LinkList L; //Deklarieren Sie einen Zeiger auf eine einfach verknüpfte Liste //Eine leere Tabelle initialisieren InitList(L); //...Folgender Code } //Bestimmen Sie, ob die einfach verknüpfte Liste leer ist (mit Header) bool Empty(LinkList L){ if(L->next==NULL) return true; anders falsch zurückgeben; }
Einfügen und Löschen einer einfach verknüpften Liste
einfügen
In Bit-Reihenfolge einfügen
//Element e (Kopfknoten) an der i-ten Position in Bitreihenfolge einfügen ListInsert(&L,int i,ElemType e){ if(i<1) falsch zurückgeben; LNode *p; //Zeiger p zeigt auf den aktuell gescannten Knoten int j=0; //Auf welchen Knoten zeigt das aktuelle p? p=L; //L zeigt auf den Kopfknoten, der der 0. Knoten ist (keine Daten gespeichert) while(p!=NULL&&j<i-1){ //Schleife, um den i-1. Knoten zu finden p=p->next; J; } if(p=NULL) //Der Wert von i ist illegal falsch zurückgeben; LNode *s =(LNode *)malloc(sizeof(LNode));//Anwenden für einen neuen Knotenraum zum Speichern neuer Elemente s->data=e; //Das Datenfeld des neuen Knotens speichert den neuen Elementinhalt s->next=p->next; // Der nächste Zeiger des neuen Knotens zeigt auf den nächsten Zeiger, auf den der i-1-Knoten zeigt, der als i-tes Element bezeichnet wird p->next=s; //Der vorherige Knoten des neuen Knotens zeigt auf den neuen Knoten return true; } typedef struct LNode{ ElemType-Daten; struct LNode *next; }LNode,*LinkList;
////Element e an der i-ten Position in Bitreihenfolge einfügen (ohne den Kopfknoten) bool ListInsert(LinkList &L,int i,ElemType e){ if(i<1) falsch zurückgeben; if(i==1){ // Der Vorgang des Einfügens am ersten Knoten unterscheidet sich von dem Vorgang anderer Knoten LNode *s=(LNode *)malloc(sizeof(LNode)); s->data=e; s->next=L; L=s; //Der Kopfzeiger zeigt auf den neuen Knoten return true; } LNode *p; int j=1; p=L; while(p!=NULL && j<i-1){ p=p->next; J; } if(p==NULL) falsch zurückgeben; s->data=e; s->next=p->next; p->next=s; return true; //Einfügung erfolgreich } typedef struct LNode{ ElemType-Daten; struct LNode *next; }LNode,*LinkList;
Post-Insert-Vorgang des angegebenen Knotens
//Nach dem Einfügevorgang Element e nach Knoten p einfügen bool InsertNextNode(LNode *p,ElemType e){ if(p==NULL) LNode *s=(LNode *)malloc(sizeof(LNode)); if(s==NULL) //Unzureichende Speicherzuweisung falsch zurückgeben; s->data=e; //Knoten s verwenden, um Datenelement e zu speichern s->next=p->next; p->next=s; //Knoten s mit nach p verbinden return true; } typedef struct LNode{ ElemType-Daten; struct LNode *next; }LNode,*LinkList;
Vorwärtseinfügungsvorgang des angegebenen Knotens
Fügen SiePriorNode(LinkList L,LNode *p,ElemType e) ein und durchlaufen Sie dann die gesamte Tabelle, um den vorherigen Knoten von p zu finden. Der Einfachheit halber kopieren Sie diesen Knoten direkt und ändern den Inhalt dieses Knotens, wodurch die Zeit erreicht wird kompliziert. Der Grad ist O(n)
// Einfügeoperation weiterleiten, Knoten s vor Knoten p einfügen bool InsertPriorNode(LNode *p,LNode *s){ if(p==NULL || s==NULL) falsch zurückgeben; s->next=p->next; p->next=s; ElemType temp=p->data; p->data=s->data; s->data=temp; return true; }
löschen
In Bitreihenfolge löschen
ListDelete(&L,i,&e): Löschvorgang. Löschen Sie das Element an Position i in Tabelle L und geben Sie mit e den Wert des gelöschten Elements zurück.
//Einfach verknüpfte Liste wird in Bitreihenfolge gelöscht bool ListDelete(LinkList &L,int I,ElemType &s){ if(i<1) falsch zurückgeben; LNode *p; //Zeiger p zeigt auf den aktuell gescannten Knoten int j=0; //j gibt an, auf welchen Knoten p aktuell zeigt p=L; //L zeigt auf den Kopfknoten, der der 0. Knoten ist (keine Daten gespeichert) while(p!=NULL&&j<j-1){ //Schleife, um den i-1. Knoten zu finden p=p->next; J; } if(p==NULL) //i Wert ist unzulässig falsch zurückgeben; if(p->next==NULL) //Es gibt keine weiteren Knoten nach dem i-1. Knoten falsch zurückgeben; LNode *q=p->next; // Lassen Sie q auf den gelöschten Knoten zeigen e=q->data; //Verwenden Sie e, um den Wert des Elements zurückzugeben p->next=q->next; //"Trennen" Sie den *q-Knoten von der Kette free(q); //Den Speicherplatz des Knotens freigeben return true; //Erfolgreich löschen } typedef struct LNode{ ElemType-Daten; struct LNode *next; }LNode,*LinkList;
Löschung des angegebenen Knotens
DeleteNode(LNode *p), Zeiger p löschen
//Löschen Sie den angegebenen Knoten p aus der einfach verknüpften Liste bool DeleteNode (LNode *p){ if(p==NULL) falsch zurückgeben; LNode *q=p->next; // q zeige auf den Nachfolgeknoten von *p p->data=p->next->data; //Datenfelder mit nachfolgenden Knoten austauschen p->next=q->next; //"Trennen" Sie den *q-Knoten von der Kette free(q); // Den Speicherplatz nachfolgender Knoten freigeben return true; }
Suche in einer einfach verknüpften Liste
Bitweise Suche
//Bitweise Suche in einfach verknüpften Listen LNode *GetElem(LinkList L,int i){ if(i<0) return NULL; LNode *p; int j=0; p=L; while(p!=NULL&&j<1){ p=p->next; J; } Rückkehr p; }
Nach Wert suchen
LocateElem(LinkList L,ElemType e) findet den Standort des Knotens mit dem Datenfeld e
//Suche nach Wert in einer einfach verknüpften Liste und finde den Knoten, dessen Datenfeld ==e zurückgibt LNode *LocateElem(LinkList L,ElemType e){ LNode *p = L->next; // Beginnen Sie mit dem ersten Knoten, um den Knoten mit dem Datenfeld e zu finden while(p != NULL&&p->data!=e) p=p->next; return p; // Den Knotenzeiger zurückgeben, nachdem er gefunden wurde, andernfalls NULL zurückgeben }
Finden Sie die Länge der Tabelle
//Tabellenlänge ermitteln int length(LinkList L){ int len=0; LNode *p=L; while(p->next != NULL){ p=p->next; len ; } return len; }
Erstellung einer einfach verknüpften Liste
Schritt 1: Initialisieren Sie eine einfach verknüpfte Liste Schritt 2: Entfernen Sie jeweils ein Datenelement und fügen Sie es am Kopf/Fuß der Tabelle ein
Methode zum Einführen des Schwanzes
Initialisieren Sie eine einfach verknüpfte Liste, legen Sie die variable Länge fest, um die Länge der verknüpften Liste aufzuzeichnen, legen Sie den Endzeiger der Liste fest und fügen Sie jeweils ein Datenelement am Ende der Liste ein.
//Tail-Einfügungsmethode zum Erstellen einer einfach verknüpften Liste LinkList List_TailInsert(LinkList &L){ //Erstellen Sie vorwärts eine einfach verknüpfte Liste int x; // ElemType auf Ganzzahl setzen L=(LinkList)malloc(sizeof(LNode)); //Erstelle den Kopfknoten LNode *s,*r=L; //r ist der Endzeiger der Tabelle scanf(“%d”,&x); //Geben Sie den Wert des Knotens ein while(x!9999){ //Geben Sie 9999 ein, um das Ende anzuzeigen s=(LNode *)malloc(sizeof(LNode)); s->data=x; r->next=s; r=s; //r zeigt auf den neuen Endzeiger der Tabelle scanf(“%d”,&x); } r->next=NULL; //Setze den Endknotenzeiger auf Null Rückkehr L; }
Methode zum Einsetzen des Kopfes
//Kopfeinfügungsmethode erstellt eine einfach verknüpfte Liste LinkList List_HeadInsert(LinkList &L){ //Umgekehrt eine einfach verknüpfte Liste erstellen LNode *s; int x; L=(LinkList)malloc(sizeof(LNode)); //Erstelle den Kopfknoten L->next=NULL; //Anfangs leere verknüpfte Liste scanf(“%d”,&x); //Geben Sie den Wert des Knotens ein while(x!=9999){ //Geben Sie 9999 ein, um das Ende anzuzeigen s=(LNode*)malloc(sizeof(LNode)); //Neuen Knoten erstellen s->data=x; s->next=L->next; L->next=s; //Füge den neuen Knoten in die Tabelle ein, L ist der Kopfzeiger scanf(“%d”,&x); } Rückkehr L; }
Doppelt verknüpfte Liste
Initialisierung einer doppelt verknüpften Liste
Einfach verknüpfte Liste: Eine einfach verknüpfte Liste kann nicht umgekehrt abgerufen werden, was manchmal unpraktisch ist. Doppelt verknüpfte Liste: kann vor- und zurückgehen, geringere Speicherdichte
//Initialisierung der doppelt verknüpften Liste (Lead-Knoten) bool InitDLinkList(DLinklist &L){ L=(DNode *)malloc(sizeof(DNode)); if(L==NULL) Rücklaufflamme; L->prior=NULL; L->next=NULL; return true; } void testDLinkList(){ //Doppelt verknüpfte Liste initialisieren DLinklist L; InitDLinkList(L); //...Folgender Code } typedef struct DNode{ ElemType-Daten; struct DNode *prior,*next; }DNode,*DLinklist; //Bestimmen Sie, ob die doppelt verknüpfte Liste leer ist (Hauptknoten) bool Empty(DLinklist L){ if(L->next==NULL) return true; anders falsch zurückgeben; }
Einfügen in eine doppelt verknüpfte Liste
//Einfügung in eine doppelt verknüpfte Liste bool InsertNextDNode(DNode *p,DNode *s){ s->next=p->next; //Knoten *s nach Knoten *p einfügen p->next->prior=s; s->prior=p; p->next=s; }
Löschen der doppelt verknüpften Liste
//Doppelt verknüpfte Liste löschen bool DeleteNextDNode(DNode *p){ if(p==NULL) return flase; DNode *q=p->next; //Nachfolgeknoten q von p finden if(q==NULL) return false; //p hat keinen Nachfolgeknoten p->next=q->next; if(q->next!=NULL) //Der q-Knoten ist nicht der letzte Knoten q->next->prior=p; free(q); //Knotenplatz freigeben return true; } void DestoryList(DLinklist &L){ //Schleife, um jeden Datenknoten freizugeben while(L->next!=NULL) DeleteNextDNode(L); free(L); //Den Kopfknoten freigeben L=NULL; //Kopfzeiger zeigt auf NULL }
Durchlaufen einer doppelt verknüpften Liste
//Durchlauf einer doppelt verknüpften Liste while(p!=NULL){ //Rückwärtsdurchlauf // Führen Sie die entsprechende Verarbeitung für Knoten p durch p=p->next; } while(p!=NULL){ //Vorwärtsdurchquerung p=p->prioe; } while(p->prioe!=NULL){ // Vorwärtsdurchquerung, Kopfknoten überspringen p=p->prior; }
zirkuläre verknüpfte Liste
Zirkuläre einfach verknüpfte Liste
Einfach verknüpfte Liste: Ausgehend von einem Knoten können nur nachfolgende Knoten gefunden werden, die vorherigen Knoten sind jedoch unbekannt. Zirkuläre einfach verknüpfte Liste: Ausgehend von einem Knoten können Sie jeden anderen Knoten finden.
//Definieren Sie eine kreisförmige einfach verknüpfte Liste typedef struct LNode{ //Definieren Sie den Knotentyp einer einzelnen verknüpften Liste ElemType data; //Jeder Knoten speichert ein Datenelement struct LNode *next; //data zeigt auf den nächsten Knoten }LNode,*LinkList; // Initialisieren Sie eine zirkuläre einfach verknüpfte Liste bool InitList(LinkList &L){ L=(LNode *)malloc(sizeof(LNode)); //Einen Kopfknoten zuweisen if(L==NULL) //Nicht genügend Speicher, Zuordnung fehlgeschlagen falsch zurückgeben; L->next = L; // Der nächste Kopfknoten zeigt auf den Kopfknoten return true; } //Bestimmen Sie, ob die zirkuläre einfach verknüpfte Liste leer ist bool Empty(LinkList L){ if(L->next==L) return true; anders Rücklaufflamme; } //Bestimmen Sie, ob Knoten p der Endknoten einer kreisförmigen einfach verknüpften Liste ist bool isTail(LinkList L,LNode *p){ if(p->next==L) return true; anders falsch zurückgeben; }
Zirkuläre doppelt verkettete Liste
// Leere kreisförmige doppelt verknüpfte Liste initialisieren bool InitDLinkList(DLinklist &L){ L=(DNode *)malloc(sizeof(DNode)); //Einen Kopfknoten zuweisen if(L==NULL) //Nicht genügend Speicher, Zuordnung fehlgeschlagen falsch zurückgeben; L->prior=L; // Die Priorität des Kopfknotens zeigt auf den Kopfknoten L->next=L; //next des Kopfknotens zeigt auf den Kopfknoten return true; } void testDLinkList(){ //Zirkuläre doppelt verknüpfte Liste initialisieren DLinklist L; InitDLinkList(L); //...Folgender Code } //Bestimmen Sie, ob die kreisförmige doppelt verknüpfte Liste leer ist bool Empty(DLinklist){ if(L->next==L) return true; anders falsch zurückgeben; } //Bestimmen Sie, ob Knoten p der Endknoten der kreisförmigen doppelt verknüpften Liste ist bool isTail(DLinklist L,DNode *p){ if(p->next==L) return true; anders falsch zurückgeben; } typedef struct DNode{ ElemType-Daten; struct DNode *prior,*next; }DNode,*DLinklist;
statische verknüpfte Liste
Definition
Einfach verknüpfte Liste: Jeder Knoten wird zufällig im Speicher zugewiesen. Statische verknüpfte Liste: Weisen Sie einen ganzen Abschnitt kontinuierlichen Speicherplatzes zu und platzieren Sie jeden Knoten zentral.
Codedarstellung
//Statische verknüpfte Liste definieren #define MaxSize 10 typedef sreuct{} ElemType-Daten; int next; } void testSLinkList(){ struct Node a[MaxSize]; //...Folgender Code } //Sie können auch eine statische verknüpfte Liste mit dem folgenden Code erstellen #define MaxSize 10 //Maximale Länge der statisch verknüpften Liste typedef struct{ //Definition des Strukturtyps der statischen verknüpften Liste ElemType-Daten; //Speicherdatenelemente int next; //Array-Index des nächsten Elements } SLinkList[MaxSize]; void testSLinkLst(){} SLinkList a; //...Folgender Code }
Implementierung grundlegender Operationen
Implementierung von Sequenzlisten und verknüpften Listen
logische Struktur
Es sind alles lineare Tische und lineare Strukturen.
Physische Struktur/Lagerungsergebnisse
Vorteile von Sequenztabellen: Unterstützung von Direktzugriff und hoher Speicherdichte. Nachteile: Es ist unpraktisch, große Bereiche kontinuierlichen Raums zuzuweisen, und es ist unpraktisch, die Kapazität zu ändern. Vorteile verknüpfter Listen: Diskrete kleine Räume lassen sich leicht zuweisen und die Kapazität lässt sich leicht ändern. Nachteile: Kein wahlfreier Zugriff, geringe Speicherdichte.
Datenoperationen/Grundoperationen
Erstellung der Sequenztabelle: Es muss ein großer zusammenhängender Raum vorab reserviert werden. Wenn der zugewiesene Speicherplatz zu klein ist, ist eine spätere Erweiterung der Kapazität unpraktisch. Wenn der zugewiesene Speicherplatz zu groß ist, werden Speicherressourcen verschwendet. Statische Zuweisung: statisches Array, unveränderliche Kapazität Dynamische Zuordnung: Dynamisches Array (malloc, kostenlos), die Kapazität kann geändert werden, es ist jedoch das Verschieben einer großen Anzahl von Elementen erforderlich, was zeitaufwändig ist. Zerstörung: Länge = 0 ändern, statisch zugewiesener Speicherplatz wird automatisch zurückgefordert, dynamisch zugewiesene Malloc-Anwendungen müssen manuell freigegeben werden Das Einfügen/Löschen von Elementen erfordert das Vor- und Zurückschieben nachfolgender Elemente. Die Zeitkomplexität beträgt O(n) und der Zeitaufwand entsteht hauptsächlich durch das Verschieben von Elementen. Wenn das bewegliche Element groß ist, ist der Zeitaufwand für die Bewegung hoch. Suche: Bitweise Suche: O(1). Suche nach Wert: O(n). Wenn die Elemente in der Tabelle geordnet sind, können sie in O(log2n) Zeit gefunden werden.
Erstellung verknüpfter Listen: Sie müssen nur einen Kopfknoten zuweisen (Sie können den Kopfknoten auch weglassen und nur einen Kopfzeiger deklarieren), der später problemlos erweitert werden kann. Zerstören: Löschen Sie nacheinander jeden Knoten (kostenlos) Das Einfügen/Löschen von Elementen erfordert lediglich eine Änderung des Zeigers. Die zeitliche Komplexität beträgt O(n) und der Zeitaufwand entsteht hauptsächlich durch das Finden des Zielelements. Der Zeitaufwand für die Suche nach Elementen ist geringer. Suche: Bitweise Suche: O(n). Nach Wert suchen: O(n).
Verwenden Sie eine sequentielle Liste oder eine verknüpfte Liste: Die Länge der Liste ist schwer abzuschätzen und Elemente müssen häufig hinzugefügt, subtrahiert/gelöscht werden. Verwenden Sie daher eine verknüpfte Liste. Die Tabellenlänge kann geschätzt werden und es gibt viele Abfrage-(Such-)Vorgänge. Verwenden Sie daher eine sequentielle Tabelle. Frage: Bitte beschreiben Sie die Sequenzliste und die verknüpfte Liste ... Was ist besser, die Sequenzliste oder die verknüpfte Liste zu verwenden? Die logischen Strukturen von Sequenzlisten und verknüpften Listen sind lineare Ergebnisse und beide gehören zu linearen Listen. Die Speicherstrukturen der beiden sind jedoch unterschiedlich. Die Sequenztabelle verwendet sequentielle Speicherung ... (Merkmale, Vor- und Nachteile); Aufgrund der Verwendung unterschiedlicher Speichermethoden ist auch die Implementierungseffizienz grundlegender Vorgänge unterschiedlich. Beim Initialisieren...beim Einfügen eines Datenelements...beim Löschen eines Datenelements...beim Suchen eines Datenelements...
Anhang
Sequenztabelle
Speicherstruktur
Datenelemente, die logisch benachbart sind, sind auch physisch benachbart
Methode zur Verwirklichung
statische Zuordnung
Implementiert mit „statischem Array“
Sobald die Größe festgelegt ist, kann sie nicht mehr geändert werden
dynamische Zuordnung
Implementiert mit „dynamischem Array“
L.data=(ElemType *)malloc (sizeof(El;emType)* Größe)
Wenn die Sequenztabelle voll ist, kann malloc verwendet werden, um den maximalen Durchsatz der Sequenztabelle dynamisch zu erweitern.
Achten Sie auf malloc und freie Funktionen
Es ist notwendig, die Datenelemente in einen neuen Speicherbereich zu kopieren und den ursprünglichen Bereich mit der Free-Funktion freizugeben.
Merkmale
Direktzugriff
Kann das i-te Element in O(1)-Zeit finden
Hohe Lagerdichte
Eine Kapazitätserweiterung ist unbequem
Das Einfügen und Löschen von Datenelementen ist umständlich
linearer Tisch
logische Struktur
Grundlegende Berechnungen/Operationen
Lagerung/physische Struktur
Sequenztabelle (sequentielle Speicherung)
Definition (wie man es im Code implementiert)
Implementierung grundlegender Operationen
Verknüpfte Liste (verknüpfter Speicher)
Einzelliste
Definition (wie man es im Code implementiert)
Implementierung grundlegender Operationen
Doppelt verknüpfte Liste
zirkuläre verknüpfte Liste
statische verknüpfte Liste
Einfügen und Löschen einer Sequenztabelle
einfügen
ListInsert(&L,i,e)
Fügen Sie das Element e an der i-ten Position von L ein
Elemente nach der Einfügeposition müssen nach hinten verschoben werden und die Länge der Tabelle wird um 1 erhöht
Zeitkomplexität
Bestes O(1), schlechtestes O(n), durchschnittliches O(n)
löschen
ListDelete(&L,i,&e)
Löschen Sie das i-te Element von L und geben Sie es mit e zurück
Elemente nach der gelöschten Position müssen nach vorne verschoben werden und die Tabellenlänge wird um 1 reduziert
Zeitkomplexität
Bestes O(1), schlechtestes O(n), durchschnittliches O(n)
Codepunkte
Beachten Sie den Unterschied zwischen der Bitreihenfolge i und dem Array-Index
Der Algorithmus muss robust sein und die Legalität von i bestimmen
Achten Sie darauf, ob das verschobene Element am vorderen Element oder am hinteren Element beginnt.
Analysieren Sie, warum es „&“ gibt
Suche nach Sequenztabellen
Bitweise Suche
GetElem(L,i)
Ermitteln Sie den Wert des Elements an Position i in Tabelle L
Verwenden Sie den Array-Index, um das i-te Element L.data[i-1] abzurufen
Zeitkomplexitätsanalyse
Die beste/schlechteste/durchschnittliche Zeitkomplexität ist O(1)
Nach Wert suchen
LocateElem(L,e)
Suchen Sie in der Sequenzliste L das Element, dessen erster Elementwert gleich e ist, und geben Sie seine Bitreihenfolge zurück
Suche beginnend beim ersten Element und rückwärts
Zeitkomplexitätsanalyse
Die beste Zeitkomplexität ist O(1)
Schlechteste Zeitkomplexität O(n)
Durchschnittliche Zeitkomplexität O(n)
Definition einer einfach verknüpften Liste
Was ist eine einfach verknüpfte Liste?
Durch die Verwendung von „Kettenspeicher“ (Speicherstruktur) wird eine „lineare Struktur“ (logische Struktur) realisiert.
Ein Knoten speichert ein Datenelement
Die Sequenzbeziehung zwischen jedem Knoten wird durch einen Zeiger dargestellt
Definieren Sie eine einfach verknüpfte Liste mithilfe von Code
typedef struct LNode{ //Definieren Sie den Knotentyp einer einzelnen verknüpften Liste ElemType-Daten; //Datenfeld struct LNode *next; //Zeigerfeld }LNode,*LinkList;
Zwei Implementierungen
Führender Knoten
Beurteilung der leeren Tabelle: L==NULL
Einfach zu schreibender Code
Kein führender Knoten
Beurteilung der leeren Tabelle: L->next==NULL;
Das Schreiben von Code ist unbequem
Weitere zu beachtende Punkte
So verwenden Sie das Schlüsselwort typedef
LinkList entspricht LNode LinkList betont eine verknüpfte Liste; LNode betont einen Knoten
Einfügen und Löschen einer einzelnen verknüpften Liste
einfügen
In Bit-Reihenfolge einfügen
Führender Knoten
Kein führender Knoten
Post-Insert-Vorgang des angegebenen Knotens
Vorwärtseinfügungsvorgang des angegebenen Knotens
löschen
In Bitreihenfolge löschen
Löschung des angegebenen Knotens
Suche in einer einfach verknüpften Liste
Bitweise Suche
Beachten Sie den Vergleich mit der „Sequenztabelle“
Eine einfach verknüpfte Liste verfügt nicht über die Eigenschaft eines „wahlfreien Zugriffs“ und kann nur sequentiell gescannt werden.
Nach Wert suchen
Ermitteln Sie die Länge einer einfach verknüpften Liste
Schlüssel
Die zeitliche Komplexität der drei Grundoperationen beträgt O(n)
So schreiben Sie Codelogik, die jeden Knoten durchläuft
Achten Sie auf die Verarbeitung der Randbedingungen
Erstellung einer einfach verknüpften Liste
Schritt 1: Initialisieren Sie eine einfach verknüpfte Liste Schritt 2: Nehmen Sie jeweils ein Datenelement und fügen Sie es am Kopf/Fuß der Tabelle ein
Methode zum Einführen des Schwanzes
Methode zum Einsetzen des Kopfes
Doppelt verknüpfte Liste
Initialisierung
Die Priorität und die nächste des Hauptknotens zeigen beide auf NULL.
Einsatz (hinterer Einsatz)
Achten Sie auf die Zeigeränderungen neu eingefügter Knoten, Vorgängerknoten und Nachfolgerknoten.
Grenzfall: Der neu eingefügte Knoten befindet sich an der letzten Position und erfordert eine Sonderbehandlung
Löschen (nachträgliches Löschen)
Achten Sie auf die Änderung der Zeiger des Vorgängerknotens und des Nachfolgerknotens des gelöschten Knotens.
Grenzfall: Wenn der gelöschte Knoten der letzte Datenknoten ist, ist eine spezielle Verarbeitung erforderlich
Traverse
Ausgehend von einem bestimmten Knoten erfolgt die Implementierung der Rückwärtsdurchquerung und der Vorwärtsdurchquerung (Beendigungsbedingung der Schleife).
Verknüpfte Listen haben keine Direktzugriffseigenschaften und Suchvorgänge können nur durch sequentielles Durchlaufen durchgeführt werden.
zirkuläre verknüpfte Liste
Zirkuläre einfach verknüpfte Liste
Leerer Tisch
nicht leere Tabelle
Zirkuläre doppelt verkettete Liste
Leerer Tisch
nicht leere Tabelle
Codeproblem
Wie man kurz urteilt
So ermitteln Sie, ob Knoten p der Kopf-/Fußknoten der Tabelle ist
zirkuläre verknüpfte Liste
Was ist eine statische verknüpfte Liste?
Weisen Sie zentral eine gesamte zusammenhängende Adresse zum Speichern von Datenelementen zu
So definieren Sie eine statisch verknüpfte Liste
Beschreiben Sie kurz die Implementierung grundlegender Operationen