日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

五大板块(4)——链表

發布時間:2023/12/10 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 五大板块(4)——链表 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

參考:五大板塊(4)——鏈表
作者:丶PURSUING
發布時間: 2021-02-15 09:33:29
網址:https://blog.csdn.net/weixin_44742824/article/details/114981905

目錄

  • 一、對比鏈表與數組
    • 同樣是存放一串數據,鏈表與數組的區別在哪里?
    • 鏈表方便增刪
  • 二、鏈表的靜態創建
    • 鏈表的動態遍歷:統計節點個數與查找節點
  • 三、插入節點與刪除節點
    • 從指定節點的后方插入新節點
    • 在指定節點前方插入新節點
    • 刪除指定節點
  • 四、鏈表的動態創建
    • 頭插法創建鏈表
    • 尾插法創建鏈表

一、對比鏈表與數組

同樣是存放一串數據,鏈表與數組的區別在哪里?

數組是申請連續的地址存放數據,在增加或刪除某一元素不方便。

而鏈表可以很好地解決這個問題。

鏈表方便增刪

大致思路:

  • 增加節點

  • 刪除節點

二、鏈表的靜態創建

#include <stdio.h>struct Test {int data;struct Test *next; };int main() {struct Test t1 ={1,NULL};struct Test t2 ={2,NULL};struct Test t3 ={3,NULL};t1.next = &t2;//t1的指針指向了t2的地址t2.next = &t3;//t1.next是一個結構體指針,訪問里面的data自然要用->printf("%d %d %d\n",t1.data,t1.next->data,t1.next->next->data);return 0; }

鏈表的動態遍歷:統計節點個數與查找節點

#include <stdio.h>struct Test {int data;struct Test *next; };//遍歷鏈表,把節點數據打印出來 void printLink(struct Test *head) {int i;struct Test *p = head;while(p != NULL){printf("%d ",p->data);p = p->next;} } //統計鏈表節點個數 void getNodeNum(struct Test *head) {int cnt = 0;struct Test *p = head;while(p != NULL){cnt++;p = p->next;}printf("鏈表節點的個數是:%d\n",cnt); }//找節點 void findNode(struct Test *head,int data) {struct Test *p = head;while(p != NULL){if(p->data == data){printf("找到了\n");return;//直接退出子函數,返回main函數}p = p->next;}printf("沒找到\n"); }int main() {struct Test t1 ={1,NULL};struct Test t2 ={2,NULL};struct Test t3 ={3,NULL};t1.next = &t2;//t1的指針指向了t2的地址t2.next = &t3;printLink(&t1);getNodeNum(&t1);findNode(&t1,2);return 0; }

結果:

1 2 3 鏈表節點的個數是:3 找到了
  • 1
  • 2

要重點理解的是:p = p->next
指針p指向了下一個結構體的地址,p->next中存放的正是下一個鏈表節點的地址。
p本身是一個結構體指針,所以用->訪問成員next.

三、插入節點與刪除節點

從指定節點的后方插入新節點

思路:
(1)找到指定節點
(2)把指定節點的的next指向new節點的地址
(3)new節點的next指向下一個節點

靠,真拗口,看圖!

舉例:要從鏈表1 2 3 4 中,在 2 后插入 5 。

#include <stdio.h>struct Test {int data;struct Test *next; };void addBehind(struct Test *head,int data,struct Test *new) {struct Test *p = head;while(p != NULL){if(data == p->data){new->next = p->next;//先連新節點的后面p->next = new; //再連新節點的前面return;}p = p->next;} }void printLink(struct Test *head) {int i;struct Test *p = head;while(p != NULL){printf("%d ",p->data);p = p->next;}putchar('\n'); }int main() {struct Test t1 ={1,NULL};struct Test t2 ={2,NULL};struct Test t3 ={3,NULL};struct Test t4 ={4,NULL};t1.next = &t2;//t1的指針指向了t2的地址t2.next = &t3;t3.next = &t4;struct Test new ={5,NULL};addBehind(&t1,2,&new);printLink(&t1);return 0; }

結果:

1 2 5 3 4
  • 1

思考一下,為什么上面要傳入結構體new的地址?

像下圖一樣修改,傳入的是結構體變量new,然后p->next再指向new的地址不就行啦?還不是一樣把地址串了起來。

void addBehind(struct Test *head,int data,struct Test new) {struct Test *p = head;while(p != NULL){if(data == p->data){new.next = p->next;p->next = &new;//形參函數結束就釋放了 p->next指向這個位置會發生斷錯誤return;}p = p->next;} }addBehind(&t1,2,new);

結果是:段錯誤

Segmentation fault
  • 1

為啥?

因為上述中new只是子函數的一個形式參數罷了,地址空間是臨時分配,當函數調用結束空間回收,你讓一個指針p->next指向這里,必然導致段錯誤!

在指定節點前方插入新節點

第一種情況:不是1之前插入,鏈表頭未發生改變

第二種情況:是在1之前插入,鏈表頭發生改變

舉個栗子:(1)要從鏈表1 2 3 4 中,在 3 前插入 5 。

#include <stdio.h>struct Test {int data;struct Test *next; };struct Test *addInfront(struct Test *head,int data,struct Test *new) {struct Test *p = head;if(data == head->data){new->next = head; //先連新節點的后面head = new;return head;}while(p->next != NULL){if(data == p->next->data){new->next = p->next;//先連新節點的后面p->next = new; //再連新節點的前面return head;}p = p->next;//讓鏈表遍歷起來} }void printLink(struct Test *head) {int i;struct Test *p = head;while(p != NULL){printf("%d ",p->data);p = p->next;}putchar('\n'); }int main() {struct Test t1 ={1,NULL};struct Test t2 ={2,NULL};struct Test t3 ={3,NULL};struct Test t4 ={4,NULL};t1.next = &t2;//t1的指針指向了t2的地址t2.next = &t3;t3.next = &t4;struct Test new ={5,NULL};struct Test *head = &t1;head = addInfront(head,3,&new);printLink(head);return 0; }

結果:

1 2 5 3 4
  • 1

(2)更改程序,在1之前插入5,結果:

5 1 2 3 4
  • 1

刪除指定節點


刪除的是頭節點時,還要注意新頭的替換

舉例:刪除 1 2 3 4中的 1

#include <stdio.h>struct Test {int data;struct Test *next; };struct Test *deNode(struct Test *head,int data) {struct Test *p = head;if(data == head->data){head = head->next;return head;}while(p->next != NULL){if(data == p->next->data){p->next = p->next->next;return head;}p = p->next;} }void printLink(struct Test *head) {int i;struct Test *p = head;while(p != NULL){printf("%d ",p->data);p = p->next;}putchar('\n'); }int main() {struct Test t1 ={1,NULL};struct Test t2 ={2,NULL};struct Test t3 ={3,NULL};struct Test t4 ={4,NULL};t1.next = &t2;//t1的指針指向了t2的地址t2.next = &t3;t3.next = &t4;struct Test *head = &t1;head = deNode(head,1);printLink(head);return 0; }

結果:

2 3 4
  • 1

刪除 1 2 3 4中的4,結果:

1 2 3
  • 1

四、鏈表的動態創建

頭插法創建鏈表

頭一直是在變化的
關鍵步驟:

new->next = head;//new直接指向原來的鏈表頭
head = new;//賦予新的鏈表頭

實際例子:

運用頭插法創建鏈表,直接輸入數據自動串成鏈表,想要結束時,輸入數據999.

#include <stdio.h> #include <stdlib.h> #include <string.h>typedef struct test {int data;struct test *next; }test,*ptest;void printLink(ptest head) {int i;ptest p = head;while(p != NULL){printf("%d ",p->data);p = p->next;}putchar('\n'); }ptest insertHead(ptest head,ptest new) {if(head == NULL){head = new;}else{new->next = head;//先連新節點的后面 new往前拱head = new; //再連新節點的前面 new變成新頭(頭插)}return head;}ptest creatLink(ptest head) {ptest new;while(1){new = (ptest)malloc(sizeof(test));printf("請輸入新的節點,輸入999結束輸入\n");scanf("%d",&new->data);if(new->data == 999){free(new);new = NULL;return head;}head = insertHead(head,new);} }int main() {ptest head = NULL;head = creatLink(head);printLink(head);return 0; }

結果:

請輸入新的節點,輸入999結束輸入 3 請輸入新的節點,輸入999結束輸入 4 請輸入新的節點,輸入999結束輸入 5 請輸入新的節點,輸入999結束輸入 6 請輸入新的節點,輸入999結束輸入 999 6 5 4 3
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

尾插法創建鏈表

關鍵步驟:

(1)遍歷找到鏈表的尾部

while(p->next != NULL){p = p->next; }
  • 1
  • 2
  • 3

(2)在尾部添加new

p->next = new;
  • 1

實際例子:

運用尾插法創建鏈表,直接輸入數據自動串成鏈表,想要結束時,輸入數據999.

#include <stdio.h> #include <stdlib.h> #include <string.h>typedef struct test {int data;struct test *next; }test,*ptest;void printLink(ptest head) {int i;ptest p = head;while(p != NULL){printf("%d ",p->data);p = p->next;}putchar('\n'); }ptest insertTail(ptest head,ptest new) {ptest p = head;if(p == NULL){head = new;return head;//沒有此句段錯誤}while(p->next != NULL){p = p->next;//遍歷找到尾巴}p->next = new;//new跟在屁股后面(尾插)return head; }ptest creatLink(ptest head) {ptest new;while(1){new = (ptest)malloc(sizeof(test));printf("請輸入新的節點,輸入999結束輸入\n");scanf("%d",&new->data);if(new->data == 999){free(new);new = NULL;return head;}head = insertTail(head,new);} }int main() {ptest head = NULL;head = creatLink(head);printLink(head);return 0; }

結果:

請輸入新的節點,輸入999結束輸入 3 請輸入新的節點,輸入999結束輸入 4 請輸入新的節點,輸入999結束輸入 5 請輸入新的節點,輸入999結束輸入 999 3 4 5
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

思考:當上面的inserTail函數更改為如下,會發生什么?

ptest insertTail(ptest head,ptest new) {ptest p = head;if(head == NULL){head = new;}else{p->next = new;}return head; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

結果:可以發現無論怎樣輸入鏈表都只有第一個和最后一個數據

請輸入新的節點,輸入999結束輸入 1 請輸入新的節點,輸入999結束輸入 3 請輸入新的節點,輸入999結束輸入 5 請輸入新的節點,輸入999結束輸入 6 請輸入新的節點,輸入999結束輸入 8 請輸入新的節點,輸入999結束輸入 999 1 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

那是因為:使用尾插法,鏈表頭一直未改變。然而在每一次的循環中,p->next都指向new,即為每次頭都指向new。到最后鏈表中自然只有頭和最新的new啦。

總結

以上是生活随笔為你收集整理的五大板块(4)——链表的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。