Presentation is loading. Please wait.

Presentation is loading. Please wait.

大綱 單向鏈結串列 環狀串列 雙向鏈結串列 鏈結串列的應用.

Similar presentations


Presentation on theme: "大綱 單向鏈結串列 環狀串列 雙向鏈結串列 鏈結串列的應用."— Presentation transcript:

0 Data Structure in C ─ 鏈結串列

1 大綱 單向鏈結串列 環狀串列 雙向鏈結串列 鏈結串列的應用

2 鏈結串列 以陣列方式存放資料,若要插入(insert)或刪除(delete)某一節點(node)就備感困難
Ex. 陣列中已有a, b, d, e四個元素,若要將c插入d, e需往後一格 Ex.陣列中已有a, b, d, e四個元素,若要將d刪除為不浪費空間需挪移元素 利用鏈結串列(linked list) 解決問題

3 鏈結串列 (續) 陣列 vs. 鏈結陣列

4 單向鏈結串列 單向鏈結串列 (single linked list)
若單向串列中的每個節點(node)的資料結構有兩個欄位,分別為資料欄(data)及鏈結欄(next), ,若將節點定義為struct型態,為 struct node{ int data; struct node *next; }; struct node *head=NULL, *tail, *this, *prev, *x, *p, *ptr;

5 單向鏈結串列 (續) Ex. 串列A={a, b, c, d, e},以鏈結串列表示為 指向串列前端的指標 指向串列尾端的指標

6 單向鏈結串列 (續) 單向鏈結串列的加入動作 加入於串列的前端 加入於串列的尾端 加入在串列某一特定節點後面

7 加入於串列的前端 Step 1: x = (struct node *) malloc(sizeof(struct node));
x->next = NULL; Step 2: x->next = head;

8 加入於串列的尾端 Step 3: head = x;
Step 1: x = (struct node *) malloc(sizeof(struct node)); x->next = NULL;

9 Step 2: tail->next = x;
Step 3: tail = x; 若未用tail指標,則每次 都必須要追蹤串列的尾端

10 加入在串列某一特定節點後面 Assumption: 將一個節點x加在ptr所指節點後面
Step 1: x = (struct node *) malloc(sizeof(struct node)); x->next = NULL; Step 2: x->next = ptr->next;

11 Step 3: ptr->next = x;

12 void insert_node(struct node. ptr, struct node. head, struct node
void insert_node(struct node *ptr, struct node *head, struct node *tail) { struct node *this if(head == NULL) /* 插入資料為第一筆 */ { ptr->next=NULL; head=ptr; tail=ptr;} else { this=head; if(ptr->key > this->key) /* 插入位置為前端 */ { ptr->next=this; head=ptr; }

13 else {while(this->next != NULL) { prev=this; this=this->next; if(ptr->key > this->key) /* 插入位置於中間 */ { ptr->next=this; prev->next=ptr; break; } } if(ptr->key <= this->score) /* 插入資料於尾端 */ { ptr->next=NULL; this->next=ptr; tail=ptr; }

14 單向鏈結串列 (續) 單向鏈結串列的刪除動作 刪除串列前端的節點 刪除串列尾端的節點 刪除串列某一特定節點

15 刪除串列前端的節點 Step 1: ptr = head; Step 2: head = ptr->next;
Step 3: free(ptr);

16 刪除串列尾端的節點 ptr = head; Step 1:必須先追蹤tail的前一個節點
while (ptr->next != tail) ptr = ptr->next; Step 1:必須先追蹤tail的前一個節點 Step 2: ptr->next = NULL; Step 3: free(tail); Step 4: tail = ptr;

17 刪除串列某一特定節點 Step 1:尋找所要刪除的節點,並設定兩指標this及prev 即將被刪除的前一節點 即將被刪除節點
while (this->next != NULL) prev = this; this = this->next;

18 Step 2: prev->next = this->next;
Step 3: free(this);

19 void delete_f(int del_key, struct node *head, struct node *tail)
{ struct node *clear, *this, *prev; this=head; if(del_key == head->key) { /* 刪除資料於前端 */ clear=this; if(head->next == NULL) /* 資料僅存在一筆 */ tail=NULL; head=head->next; free(clear); } while(this->next != NULL) { /* 刪除資料於中間 */ prev=this; this=this->next; if (del_key == this->key) { prev->next=this->next; free(clear); } } if(del_key == tail->key) { /*刪除資料於尾端 */ prev->next=NULL; tail=prev;

20 單向鏈結串列 (續) 將兩串列相接 三種情況 x串列為NULL,y串列有資料 x串列有資料,y串列為NULL x串列與y串列都有資料

21 void concatenate (struct node *x, struct node *y, struct node *y)
{ struct node *c; if (x = = NULL) z = y; else if (y = = NULL) z = x; else { z=x; c=x; while(c->next != NULL) c = c->next; c->next = y; }

22 將一串列反轉 串列的反轉是將原先的串列首變成串列尾 Ex. 若一串列原先以小排到大,此時若想由大到小排列
void invert(struct node *head) { struct node *this, *prev, *next_n; next_n = head; this =NULL; while(next_n != NULL){ prev = this; this = next_n; next_n = next->next; this->next = prev; } tail = head; head = this;

23 單向鏈結串列 (續) 計算串列的長度 串列長度指的是此串列共有多少個節點,計算上只要指標指到的為NULL,則利用一變數做累加,直到指標指到NULL為止 int length(struct node *head) { struct node *this; this = head; int leng=0; while (this != NULL) { leng++’ this = this->next;} return leng; }

24 環狀串列 假若將鏈結串列最後一個節點的指標指向第一個節點時,此串列稱為環狀串列(circular list)
可以由任一點來追蹤所有節點,而不必區分那一個是第一個節點

25 環狀串列 (續) 環狀串列的加入動作 加入於串列的前端 加入於串列的尾端 加入在串列某一特定節點後面 若串列為空串列(NULL)
若串列不為空串列 加入於串列的尾端 加入在串列某一特定節點後面

26 加入於串列的前端 ─ 串列為空串列 加入於串列的前端 ─ 串列不為空串列 Step 1: head = x; tail=x;
Step 2: x->next = x; 加入於串列的前端 ─ 串列不為空串列 Step 1: x->next = head;

27 Step 2: tail->next = x;
Step 3: head = x;

28 加入於串列的尾端 Step 2: x->next = head; Step 1: tail->next = x;
Step 3: tail = x;

29 void insert_node(struct node. ptr, struct node. head, struct node
void insert_node(struct node *ptr, struct node *head, struct node *tail) { struct node *prev, *this; if(head == NULL) { /* 插入資料為第一筆 */ ptr->next = ptr; head = ptr; tail = ptr; } else { this = head; if(ptr->key < this->key) { /* 插入位置為前端 */ ptr->next = this; tail->next = head; } else { while(this->next != head) { prev = this; this = this->next;

30 if(ptr->key < this->key) { /* 插入位置於中間 */
ptr->next = this; prev->next = ptr; break; } } if( ptr->key >= this->key) { /* 插入資料於尾端 */ ptr->next = head; this->next = ptr; tail = ptr; }

31 環狀串列 (續) 環狀串列的刪除動作 刪除串列前端的節點 刪除串列尾端的節點 刪除串列某一特定節點

32 刪除串列前端的節點 Step 1: tail->next = head->next;
Step 2: ptr=head; head = head->next; Step 3: free(ptr);

33 刪除串列尾端的節點 ptr = head; Step 1: 必須先追蹤tail的前一個節點
while (ptr->next != tail) ptr = ptr->next; Step 1: 必須先追蹤tail的前一個節點 Step 2: ptr->next = hear; Step 3: free(tail); tail=ptr;

34 void delete_node(int del_key, struct node *head, struct node *tail)
{ struct node *clear, *prev, *this; this = head; if(del_key == head->key) { /* 刪除資料於前端 */ clear = head; if(head->next == head) /* 資料僅存在一筆 */ {head = NULL; tail = NULL;} else { head = head->next; tail->next = head; } }

35 while(this->next != head && head != NULL) /* 刪除資料於中間 */
{ prev = this; this = this->next; if(del_key == ,this->key) { clear = this; prev->next = this->next; tail = prev; } } if(del_key == tail->key) { /*刪除資料於尾端 */ clear = tail; prev->next = head; free(clear);

36 將兩串列相接 Step 1: Atail->next = Bhead; Step 2: Btail->next = Ahead;

37 雙向鏈結串列 雙向鏈結串列(doubly linked list)
每個節點有三個欄位,一為左鏈結(LLink),二為資料(Data),三為右鏈結(RLink) 特點: 假設ptr是任何節點的指標,則 ptr = ptr->llink->rlink = ptr->rlink->llink; 若此雙向鏈結串列是空串列,則只有一個串列首

38 雙向鏈結串列 (續) 優點: 缺點: 加入或刪除時,無需知道其前一節點的位址 可以從任一節點找到其前一節點或後一節點
可以將某一節點遺失的左或右指標適時地加以恢復之 缺點: 增加一個指標空間 加入時需改變四個指標(單向只需改變兩個指標) 刪除時需改變兩個指標(單向只要改變一個指標)

39 雙向鏈結串列 (續) 雙向鏈結串列的加入動作 加入於串列的前端 加入於串列的尾端 加入在串列某一特定節點後面 假設head節點不放任何資料
void init_head(struct node *ptr, struct node *head, struct node *tail) { ptr = (struct node *) malloc (sizeof(struct node)); ptr->key = NULL; ptr->llink = ptr; ptr->rlink = ptr; head = ptr; tail = ptr;} 假設head節點不放任何資料

40 加入於串列的前端 Step 1: x->rlink = head; Step 2: x->llink = tail;
Step 3: tail->rlink = x;

41 Step 4: head->rlink = x;
Step 5: tail = x;

42 加入於串列的尾端 Assumption: 假設有一串列如下 Step 1: x->rlink = tail->rlink;
Step 2: tail->rlink = x;

43 Step 3: x->llink = tail;
Step 4: head->llink = x; Step 5: tail = x;

44 雙向鏈結串列 (續) 加入在串列某一特定節點後面 必須先搜尋到某特定的節點,並假設此串列是以key由小而大建立的,而搜尋步驟如下:
prev = head; ptr = head->rlink; while(ptr != head && x->key <p->key) { prev = ptr; ptr = ptr->rlink; }

45 void insert_node(struct node. ptr, struct node. head, struct node
void insert_node(struct node *ptr, struct node *head, struct node *tail) { struct node *this; this = head->rlink; while(this != head) { if(ptr->key < this->key) { /* 插入位置為中間 */ ptr->rlink = this; ptr->llink = this->llink; this->llink->rlink = ptr; this->llink = ptr; break; } this = this->rlink; } /* 插入位置為尾端 */ if(head->rlink == head || this == head) { ptr->rlink = head; ptr->llink = head->llink; head->llink->rlink = ptr; head->llink = ptr; tail = ptr;} }

46 雙向鏈結串列 (續) 雙向鏈結串列的刪除動作 刪除串列前端的節點 刪除串列尾端的節點 刪除串列某一特定節點

47 刪除串列前端的節點 Step 1: ptr = head->rlink;
Step 2: head->rlink = ptr->rlink; Step 3: p->rlink->llink = p->llink; Step 4: free(ptr);

48 刪除串列尾端的節點 Step 1: tail->llink->rlink = head;
Step 2: head->llink = tail->llink; Step 3: ptr = tail; Step 4: tail = tail->llink; Step 5: free(ptr);

49 刪除串列某一特定節點 Assumption: 假設欲刪除this所指的節點
Step 1: this->llink->rlink = this->rlink; Step 2: this->rlink->llink = this->llink; Step 3: free(this);

50 void delete_node(int del_key, struct node *head, struct node *tail)
{ struct node *clear, *this; this = head->rlink; while(this != head) { /* 刪除資料於中間 */ if(del_key == this->key) { clear = this; this->llink->rlink = this->rlink; this->rlink->llink = this->llink; if(this == tail) tail = this->llink; break; } this = this->rlink; } free(clear);

51 鏈結串列的應用 以鏈結串列表示堆疊 以鏈結串列表示佇列 以鏈結串列表示多項式相加

52 鏈結串列的應用 (續) 以鏈結串列表示堆疊 將堆疊內的資料視為單向鏈結串列中的資料項 Push: 視為將節點加入串列的前端
Pop: 視為刪除前端的節點

53 鏈結串列的應用 (續) 以鏈結串列表示堆疊 ─ Push
void push_stack(int data, struct node *ptr, struct node *top) {ptr = (struct node *) malloc(sizeof(struct node)); ptr->item = data; ptr->next = top; top = ptr; }

54 鏈結串列的應用 (續) 以鏈結串列表示堆疊 ─ Pop void pop_stack(int data, struct node *top)
{struct node *clear if(top ==NULL) printf(“stack-empty”); clear = top; data = top->item; top = top->next; free(clear); }

55 鏈結串列的應用 (續) 以鏈結串列表示佇列 將佇列內的資料視為單向鏈結串列中的資料項 Enqueue:視為將節點加入串列的尾端
Dequeue:視為刪除前端的節點 由此處開始刪除 由此處開始加入

56 鏈結串列的應用 (續) 以鏈結串列表示佇列 ─ Enqueue
void enqueue(int data, struct node *front, struct node *rear) { ptr = (struct node *) malloc(sizeof(struct node)); ptr->item = data; ptr->next = NULL; if(rear == NULL) front = rear = ptr; else rear->next = ptr; rear = ptr;}

57 鏈結串列的應用 (續) 以鏈結串列表示佇列 ─ Dequeue
void dequeue(int data, struct node *front) {struct node *clear if(front ==NULL) printf(“stack-empty”); data = front->item; clear = front; front = front->next; free(clear); }

58 鏈結串列的應用 (續) 以鏈結串列表示多項式相加 多項式相加可以用鏈結串列完成,其資料結構為 原理(若有A、B兩多項式)
Coef表示變數的係數 Exp表示變數的指數 Link為指下一節點的指標 原理(若有A、B兩多項式) Exp(A) = Exp(B) Exp(A) > Exp(B) Exp(A) < Exp(B)

59 void poly_add(void) { struct poly *this_n1, *this_n2, *prev; this_n1 = eq_h1; this_n2 = eq_h2; prev = NULL; while(this_n1 != NULL || this_n2 != NULL) /* 當兩個多項式皆相加完畢則結束 */ ptr = (struct poly *) malloc(sizeof(struct poly)); ptr->next = NULL; /* 第一個多項式指數大於第二個多項式 */ if(this_n1 != NULL && (this_n2 == NULL || this_n1->exp > this_n2->exp)) ptr->coef = this_n1->coef; ptr->exp = this_n1->exp; this_n1 = this_n1->next; }

60 else /* 第一個多項式指數小於第二個多項式 */ if(this_n1 == NULL || this_n1->exp < this_n2->exp) { ptr->coef = this_n2->coef; ptr->exp = this_n2->exp; this_n2 = this_n2->next; } else /* 兩個多項式指數相等,進行相加 */ ptr->coef = this_n1->coef + this_n2->coef; ptr->exp = this_n1->exp; if(this_n1 != NULL) this_n1 = this_n1->next; if(this_n2 != NULL) this_n2 = this_n2->next;

61 if(ptr->coef != 0) /* 當相加結果不等於0,則放入答案多項式中 */
{ if(ans_h == NULL) ans_h = ptr; else prev->next = ptr; prev = ptr; } else free(ptr);


Download ppt "大綱 單向鏈結串列 環狀串列 雙向鏈結串列 鏈結串列的應用."

Similar presentations


Ads by Google