数据结构与算法 | 链表
鏈表是一種物理存儲(chǔ)結(jié)構(gòu)上非連續(xù)、非順序的存儲(chǔ)結(jié)構(gòu),數(shù)據(jù)元素的邏輯順序是通過(guò)鏈表中的指針鏈接次序?qū)崿F(xiàn)的。
對(duì)于表,圖,棧,隊(duì)列,樹(shù)等數(shù)據(jù)結(jié)構(gòu),我們采用鏈?zhǔn)胶晚樞蚪Y(jié)構(gòu)都可以實(shí)現(xiàn)。
而鏈表又分為很多種,這一次先介紹最基礎(chǔ)的鏈表
因?yàn)殒湵淼目臻g并不連續(xù),所以我們無(wú)需像順序表一樣考慮到表的容量,實(shí)現(xiàn)起來(lái)也更為簡(jiǎn)單,同時(shí),這次實(shí)現(xiàn)的鏈表是不帶頭的單向鏈表,因?yàn)闆](méi)有頭節(jié)點(diǎn),也沒(méi)有返回值,我們就需要直接對(duì)指針進(jìn)行操作,傳遞參數(shù)時(shí)就需要傳二級(jí)指針
數(shù)據(jù)結(jié)構(gòu)
typedef struct ListNode {DATATYPE data;struct ListNode* next; }ListNode;實(shí)現(xiàn)的接口
void ListPrint(ListNode* list); //打印鏈表 void ListPushBack(ListNode** list, DATATYPE x); //頭刪 void ListPushFront(ListNode** list, DATATYPE x); //頭插 void ListPopBack(ListNode** list); //尾刪 void ListPopFront(ListNode** list) //頭插 void ListInsert(ListNode** pos, DATATYPE x); //指定位置插入 void ListErase(ListNode** pos); //指定位置刪除 void ListDestory(ListNode** list); //銷毀鏈表 ListNode* ListFind(ListNode** list, DATATYPE x); //查找鏈表元素打印鏈表
void ListPrint(ListNode* list) {if (list == NULL){printf("表空\(chéng)n");return;}ListNode* cur = list;while (cur){printf("%d ", cur->data);cur = cur->next;}printf("\n"); }頭插
void ListPushFront(ListNode** list, DATATYPE x) {ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));newnode->data = x;newnode->next = NULL;newnode->next = *list;*list = newnode; }頭插:即每次在表的頭部插入,所以我們每次只需要將原頭節(jié)點(diǎn)設(shè)為插入節(jié)點(diǎn)的next節(jié)點(diǎn),然后再將這個(gè)插入的節(jié)點(diǎn)作為頭節(jié)點(diǎn)即可
如圖所示,當(dāng)我們依次插入1,2,3,4時(shí)
尾插
void ListPushBack(ListNode** list, DATATYPE x) {ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));newnode->data = x;newnode->next = NULL;if (*list == NULL){*list = newnode;}else{ListNode* tail = *list;while (tail->next){tail = tail->next;}tail->next = newnode;} }尾插:即我們常用的方式,實(shí)現(xiàn)方法是先找到鏈表的最后一個(gè)節(jié)點(diǎn),然后將他的next節(jié)點(diǎn)設(shè)為插入的節(jié)點(diǎn),再讓插入的節(jié)點(diǎn)的下一個(gè)next節(jié)點(diǎn)為空即可
頭刪
void ListPopFront(ListNode** list) {if (NULL == *list)return;ListNode* next = (*list)->next;free(*list);(*list) = next;}頭刪:我們先用next指針來(lái)保存首部的下一個(gè)節(jié)點(diǎn),然后再將首部刪除,使之前的next指針成為新的首部,即可實(shí)現(xiàn)頭刪
尾插
void ListPopBack(ListNode** list) {if (NULL == *list){printf("表空\(chéng)n");return;}else if ((*list)->next == NULL){free(*list);*list = NULL;}else{ListNode* prev = NULL, * tail = *list;while (tail->next){prev = tail;tail = tail->next;}free(tail);if (prev)prev->next = NULL;} }尾刪:尾刪的實(shí)現(xiàn)要稍微比頭刪麻煩一些,因?yàn)槲覀兊倪@個(gè)鏈表并不是雙向的,所以當(dāng)我們遍歷到最后一個(gè)節(jié)點(diǎn)的時(shí)候無(wú)法訪問(wèn)上一個(gè)節(jié)點(diǎn),我們就需要用一個(gè)prev來(lái)保存上一個(gè)節(jié)點(diǎn)的地址,當(dāng)我們遍歷到最后一個(gè)節(jié)點(diǎn)的時(shí)候,直接釋放掉這個(gè)一個(gè)節(jié)點(diǎn),然后讓prev指針的下一個(gè)節(jié)點(diǎn)指向空即可實(shí)現(xiàn)
鏈表查找
ListNode* ListFind(ListNode** list, DATATYPE x) { ListNode* cur = *list;while (cur){if (cur->data == x){return cur;}else{cur = cur->next;}}return NULL; }遍歷鏈表查找元素
在Pos位置插入
void ListInsert(ListNode** pos, DATATYPE x) {if (NULL == (*pos))return;ListNode* cur = (ListNode*)malloc(sizeof(ListNode));cur->data = x;cur->next = (*pos)->next;(*pos)->next = cur; }在Pos位置插入:讓插入的元素的next指向pos位置的next,然后再讓pos的next指向這個(gè)元素即可
在Pos位置刪除
void ListErase(ListNode** pos) {if (NULL == (*pos) || NULL == (*pos)->next)return;ListNode* next = (*pos)->next;(*pos)->next = next->next;free(next);next = NULL; }在Pos位置刪除:這里指的是刪除pos位置的后一個(gè)元素,即讓pos指針的next指向他原本的next的next,也就是pos指針往后兩個(gè)的位置
銷毀鏈表
void ListDestory(ListNode** list) {ListNode* cur = *list;while (cur){ListNode* next = cur->next;free(cur);cur = next;}*list = NULL; }具體代碼:
頭文件:
函數(shù)實(shí)現(xiàn)文件:
#include "LinkList.h"void ListPrint(ListNode* list) {if (list == NULL){printf("表空\(chéng)n");return;}ListNode* cur = list;while (cur){printf("%d ", cur->data);cur = cur->next;}printf("\n"); }void ListPushBack(ListNode** list, DATATYPE x) {ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));newnode->data = x;newnode->next = NULL;if (*list == NULL){*list = newnode;}else{ListNode* tail = *list;while (tail->next){tail = tail->next;}tail->next = newnode;} }void ListPushFront(ListNode** list, DATATYPE x) {ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));newnode->data = x;newnode->next = NULL;newnode->next = *list;*list = newnode; }void ListPopBack(ListNode** list) {if (NULL == *list){printf("表空\(chéng)n");return;}else if ((*list)->next == NULL){free(*list);*list = NULL;}else{ListNode* prev = NULL, * tail = *list;while (tail->next){prev = tail;tail = tail->next;}free(tail);if (prev)prev->next = NULL;} }void ListPopFront(ListNode** list) {if (NULL == *list)return;ListNode* next = (*list)->next;free(*list);(*list) = next;}ListNode* ListFind(ListNode** list, DATATYPE x) { ListNode* cur = *list;while (cur){if (cur->data == x){return cur;}else{cur = cur->next;}}return NULL; }void ListDestory(ListNode** list) {ListNode* cur = *list;while (cur){ListNode* next = cur->next;free(cur);cur = next;}*list = NULL; }void ListInsert(ListNode** pos, DATATYPE x) {if (NULL == (*pos))return;ListNode* cur = (ListNode*)malloc(sizeof(ListNode));cur->data = x;cur->next = (*pos)->next;(*pos)->next = cur; }void ListErase(ListNode** pos) {if (NULL == (*pos) || NULL == (*pos)->next)return;ListNode* next = (*pos)->next;(*pos)->next = next->next;free(next);next = NULL; } 超強(qiáng)干貨來(lái)襲 云風(fēng)專訪:近40年碼齡,通宵達(dá)旦的技術(shù)人生總結(jié)
以上是生活随笔為你收集整理的数据结构与算法 | 链表的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 数据结构与算法 | 顺序表
- 下一篇: 数据结构与算法 | 带头双向循环链表