1. 程式人生 > >數據結構(一)線性表雙向鏈表

數據結構(一)線性表雙向鏈表

tro i++ crt 初始 emp 交換 strong truct erro

(一)定義

雙向鏈表是在單鏈表的每個結點中,再設置一個紙箱其前驅結點的指針域

(二)結點結構

typedef struct Node
{
    ElemType data;
    struct Node* prior;    //直接前驅指針
    struct Node* next;    //直接後繼指針
}Node;

typedef struct Node* CLinkList;

(三)雙向鏈表結構

雙向循環鏈表

帶有頭結點的空鏈表

技術分享圖片

帶有頭結點的數據鏈表

技術分享圖片

對於非循環的,直接將頭結點的直接前驅指針置為空,將尾結點的直接後驅結點置為空即可

(四)實現雙向鏈表

#define
_CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <time.h> #include <math.h> #define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0 typedef char ElemType; typedef int Status; typedef struct Node { ElemType data; struct Node* prior; //直接前驅指針
struct Node* next; //直接後繼指針 }Node; typedef struct Node* DLinkList; //四個基本操作,初始化,清空,獲取長度,是否為空 Status InitList(DLinkList* Dl); Status ClearList(DLinkList* Dl); int GetLength(DLinkList Dl); Status EmptyList(DLinkList Dl); //四個插入,程序,刪除操作 Status GetElem(DLinkList Dl, int i, ElemType* e); int LocateElem(DLinkList Dl, ElemType e); Status InsertList(DLinkList
* Dl, int i, ElemType e); Status DeleteList(DLinkList* Dl, int i, ElemType* e); //打印鏈表 void PrintList(DLinkList Dl, int i); int main() { DLinkList dbList; ElemType e=A; int i = 0; InitList(&dbList);//初始化鏈表 for (; i < 26;i++) //插入數據 { //InsertList(&dbList, -1, e + i); //尾插法 InsertList(&dbList, GetLength(dbList)+1, e + i); //頭插法 } PrintList(dbList, 3); PrintList(dbList, -3); system("pause"); return 0; } //四個基本操作,初始化,清空,獲取長度,是否為空 //創建一個帶有頭結點的雙向鏈表 Status InitList(DLinkList* Dl) { DLinkList Dlist; *Dl = (DLinkList)malloc(sizeof(Node)); if (*Dl == NULL) return ERROR; (*Dl)->next = (*Dl)->prior = (*Dl); //都指向頭結點,雖然這裏數據data為char,也是可以存儲鏈表長度的,但是這裏不使用 return OK; } //清空雙向鏈表,頭結點也釋放掉 Status ClearList(DLinkList* Dl) { DLinkList Dlist = *Dl; DLinkList q; if (Dlist == NULL) return ERROR; //先將尾結點的next指針置為空,一會作為判斷循環退出條件 Dlist->prior->next = NULL; while (Dlist) { q = Dlist; Dlist = Dlist->next; free(q); } return OK; } //獲取鏈表長度,不含頭結點,使用一條單向指針域即可 int GetLength(DLinkList Dl) { DLinkList cur = Dl->next; int length = 0; while (cur!=Dl) { cur = cur->next; length++; } return length; } //判斷是否鏈表為空,判斷頭結點一個指針是否指向自己就可以 Status EmptyList(DLinkList Dl) { if (Dl->prior == Dl) return TRUE; return FALSE; } //四個插入,程序,刪除操作 //根據索引獲取數據,支持雙向索引 Status GetElem(DLinkList Dl, int i, ElemType* e) { int j = 0; DLinkList cur = Dl; if (e == NULL||i==0) return ERROR; for (; j < abs(i);j++) { if (i < 0) cur = cur->prior; else cur = cur->next; } *e = cur->data; return OK; } //按照元素進行查找,單向正向查找 int LocateElem(DLinkList Dl, ElemType e) { DLinkList cur = Dl->next; int index=1; while (cur->data != e&&cur != Dl) { cur = cur->next; index++; } if (cur == Dl) return 0; return index; } //支持雙向插入 Status InsertList(DLinkList* Dl, int i, ElemType e) { DLinkList cur = *Dl; DLinkList newNode; int j = 0; if (*Dl == NULL || abs(i) > GetLength(*Dl) + 1 || i == 0) return ERROR; for (; j < abs(i);j++) //找到他的後一個節點,一會向前推 { if (i < 0) cur = cur->prior; else cur = cur->next; } //創建一個新的結點 newNode = (DLinkList)malloc(sizeof(Node)); newNode->data = e; if (i<0) { newNode->next = cur->next; newNode->prior = cur; cur->next->prior = newNode; cur->next = newNode; } else { newNode->next = cur; newNode->prior = cur->prior; cur->prior->next = newNode; cur->prior = newNode; } return OK; } //支持雙向刪除 Status DeleteList(DLinkList* Dl, int i, ElemType* e) { DLinkList cur = *(Dl); DLinkList oldNode; int j = 0; if (*Dl == NULL || abs(i) > GetLength(*Dl) || i == 0 || e == NULL) return ERROR; for (; j < abs(i); j++) //找到要刪除的結點 { if (i < 0) cur = cur->prior; else cur = cur->next; } //賦值 *e = cur->data; oldNode = cur; //開始交換指針順序 oldNode->prior->next = oldNode->next; oldNode->next->prior = oldNode->prior; free(oldNode); return OK; } //打印鏈表,支持雙向打印,其實在main方法中稍微調整傳入的結點也可以實現 void PrintList(DLinkList Dl, int i) { DLinkList cur = Dl; DLinkList start; int j = 0; if (i==0) //若是輸入0,按照正向找到第一個結點進行輸出即可 cur = cur->next; for (; j < abs(i); j++) //找到要開始打印的最開始那個結點 { if (i < 0) cur = cur->prior; else cur = cur->next; } start = cur; //找到最開始打印的那個結點 while (cur->next!=start) //進行判斷結點 { if (cur!=Dl) //不打印頭結點 printf("%c ", cur->data); cur = cur->next; } if (cur != Dl) printf("%c", cur->data); printf("\n"); }

(五)打印預覽

技術分享圖片

(六)總結

雙向鏈表相對於單鏈表來說,要復雜些,多了個直接前驅指針,對於初入,刪除考慮的指針交換需要格外小心。而且占用空間也增加了。
但是他有良好的對稱性,是對於某個結點的前後結點的操作,帶來了方便,提高了算法時間性能。也就是使用空間來換取時間。
原來單鏈表要尋找某個結點的前一個節點的時間復雜度是O(n),使用雙向鏈表去查找前一個節點的時間復雜度是O(1)

數據結構(一)線性表雙向鏈表