欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C語言實(shí)例之雙向鏈表增刪改查

 更新時(shí)間:2023年08月15日 10:51:14   作者:DS小龍哥  
雙向鏈表(Doubly Linked List)是一種常見的數(shù)據(jù)結(jié)構(gòu),在單鏈表的基礎(chǔ)上增加了向前遍歷的功能,與單向鏈表不同,雙向鏈表的每個(gè)節(jié)點(diǎn)除了包含指向下一個(gè)節(jié)點(diǎn)的指針外,還包含指向前一個(gè)節(jié)點(diǎn)的指針,本文給大家介紹了C語言中雙向鏈表的增刪改查

一、雙向鏈表介紹

雙向鏈表(Doubly Linked List)是一種常見的數(shù)據(jù)結(jié)構(gòu),在單鏈表的基礎(chǔ)上增加了向前遍歷的功能。與單向鏈表不同,雙向鏈表的每個(gè)節(jié)點(diǎn)除了包含指向下一個(gè)節(jié)點(diǎn)的指針外,還包含指向前一個(gè)節(jié)點(diǎn)的指針。

作用和原理:

(1)插入和刪除操作:由于雙向鏈表中每個(gè)節(jié)點(diǎn)都有指向前一個(gè)節(jié)點(diǎn)的指針,所以在雙向鏈表中進(jìn)行插入或刪除操作時(shí),相對(duì)于單向鏈表更加高效??梢酝ㄟ^修改前后節(jié)點(diǎn)的指針來完成插入和刪除,而無需遍歷鏈表。

(2)雙向遍歷:雙向鏈表支持從頭部到尾部以及從尾部到頭部的雙向遍歷。這在某些場(chǎng)景下非常有用,例如需要反向查找、刪除最后一個(gè)節(jié)點(diǎn)等。

(3)增加了靈活性:由于每個(gè)節(jié)點(diǎn)都具有指向前一個(gè)節(jié)點(diǎn)和后一個(gè)節(jié)點(diǎn)的指針,雙向鏈表在某些特定場(chǎng)景下更靈活。例如,需要在鏈表中間插入或刪除節(jié)點(diǎn),或者需要修改前一個(gè)節(jié)點(diǎn)的信息。

雙向鏈表的原理很簡單。每個(gè)節(jié)點(diǎn)由數(shù)據(jù)域和兩個(gè)指針組成,其中一個(gè)指針指向前一個(gè)節(jié)點(diǎn),一個(gè)指針指向后一個(gè)節(jié)點(diǎn)。頭節(jié)點(diǎn)指向鏈表的第一個(gè)節(jié)點(diǎn),尾節(jié)點(diǎn)指向鏈表的最后一個(gè)節(jié)點(diǎn)。通過調(diào)整節(jié)點(diǎn)之間的指針,可以在雙向鏈表中執(zhí)行插入、刪除和遍歷等操作。

使用場(chǎng)景:

(1)編輯器中的撤銷和重做功能:雙向鏈表可以用于實(shí)現(xiàn)撤銷和重做功能,每次編輯操作都將其結(jié)果存儲(chǔ)為一個(gè)節(jié)點(diǎn),并使用指針鏈接起來。通過雙向鏈表,可以方便地在撤銷和重做之間進(jìn)行切換。

(2)瀏覽器的導(dǎo)航歷史:瀏覽器的導(dǎo)航歷史可以使用雙向鏈表來保存已訪問的頁面,每個(gè)頁面作為一個(gè)節(jié)點(diǎn),并使用指針鏈接起來,以便進(jìn)行前進(jìn)和后退操作。

(3)實(shí)現(xiàn)LRU緩存替換算法:LRU緩存中,最近最少使用的數(shù)據(jù)被淘汰,可以使用雙向鏈表來維護(hù)緩存中的數(shù)據(jù),最近訪問的數(shù)據(jù)位于鏈表的頭部,最久未訪問的數(shù)據(jù)位于鏈表的尾部。

(4)實(shí)現(xiàn)雙向隊(duì)列:雙向鏈表可以用于實(shí)現(xiàn)雙向隊(duì)列(Dequeue),支持在隊(duì)列的兩端進(jìn)行插入和刪除操作。

雙向鏈表提供了更多的靈活性和功能,特別是當(dāng)需要在雙向遍歷、頻繁的插入和刪除操作等場(chǎng)景下使用。在許多常見的數(shù)據(jù)結(jié)構(gòu)和算法中都有廣泛的應(yīng)用。

二、代碼實(shí)現(xiàn)

以下是使用C語言實(shí)現(xiàn)的完整雙向鏈表代碼,包含了鏈表的創(chuàng)建、增加、刪除、修改、排序和插入等功能。代碼中封裝了一套完整的子函數(shù),以方便使用。

#include <stdio.h>
#include <stdlib.h>
?
// 雙向鏈表節(jié)點(diǎn)結(jié)構(gòu)
typedef struct Node {
 ? ?int data; ? ? ? ? ? ? ?// 數(shù)據(jù)域
 ? ?struct Node* prev; ? ? // 指向前一個(gè)節(jié)點(diǎn)的指針
 ? ?struct Node* next; ? ? // 指向后一個(gè)節(jié)點(diǎn)的指針
} Node;
?
// 創(chuàng)建新節(jié)點(diǎn)
Node* createNode(int data) {
 ? ?Node* newNode = (Node*)malloc(sizeof(Node));
 ? ?if (newNode == NULL) {
 ? ? ? ?printf("Failed to allocate memory for new node\n");
 ? ? ? ?return NULL;
 ?  }
 ? ?newNode->data = data;
 ? ?newNode->prev = NULL;
 ? ?newNode->next = NULL;
 ? ?return newNode;
}
?
// 在鏈表末尾添加節(jié)點(diǎn)
void append(Node** head, int data) {
 ? ?Node* newNode = createNode(data);
 ? ?if (newNode == NULL) {
 ? ? ? ?return;
 ?  }
 ? ?if (*head == NULL) {
 ? ? ? ?*head = newNode;
 ?  } else {
 ? ? ? ?Node* current = *head;
 ? ? ? ?while (current->next != NULL) { ? ?// 找到鏈表末尾
 ? ? ? ? ? ?current = current->next;
 ? ? ?  }
 ? ? ? ?current->next = newNode;
 ? ? ? ?newNode->prev = current;
 ?  }
}
?
// 在鏈表頭部添加節(jié)點(diǎn)
void prepend(Node** head, int data) {
 ? ?Node* newNode = createNode(data);
 ? ?if (newNode == NULL) {
 ? ? ? ?return;
 ?  }
 ? ?if (*head == NULL) {
 ? ? ? ?*head = newNode;
 ?  } else {
 ? ? ? ?newNode->next = *head;
 ? ? ?  (*head)->prev = newNode;
 ? ? ? ?*head = newNode;
 ?  }
}
?
// 在指定位置插入節(jié)點(diǎn)
void insert(Node** head, int data, int position) {
 ? ?if (position < 0) {
 ? ? ? ?printf("Invalid position\n");
 ? ? ? ?return;
 ?  }
 ? ?if (position == 0) {
 ? ? ? ?prepend(head, data);
 ? ? ? ?return;
 ?  }
 ? ?Node* newNode = createNode(data);
 ? ?if (newNode == NULL) {
 ? ? ? ?return;
 ?  }
 ? ?Node* current = *head;
 ? ?int count = 0;
 ? ?while (count < (position - 1) && current != NULL) { ? ?// 找到插入位置前一個(gè)節(jié)點(diǎn)
 ? ? ? ?current = current->next;
 ? ? ? ?count++;
 ?  }
 ? ?if (current == NULL) {
 ? ? ? ?printf("Invalid position\n");
 ? ? ? ?free(newNode);
 ? ? ? ?return;
 ?  }
 ? ?newNode->next = current->next;
 ? ?newNode->prev = current;
 ? ?if (current->next != NULL) {
 ? ? ? ?current->next->prev = newNode;
 ?  }
 ? ?current->next = newNode;
}
?
// 刪除指定位置的節(jié)點(diǎn)
void removeAt(Node** head, int position) {
 ? ?if (*head == NULL) {
 ? ? ? ?printf("List is empty\n");
 ? ? ? ?return;
 ?  }
 ? ?if (position < 0) {
 ? ? ? ?printf("Invalid position\n");
 ? ? ? ?return;
 ?  }
 ? ?Node* current = *head;
 ? ?int count = 0;
 ? ?if (position == 0) {
 ? ? ? ?*head = current->next;
 ? ? ? ?if (*head != NULL) {
 ? ? ? ? ?  (*head)->prev = NULL;
 ? ? ?  }
 ? ? ? ?free(current);
 ? ? ? ?return;
 ?  }
 ? ?while (count < position && current != NULL) { ? ?// 找到要?jiǎng)h除的節(jié)點(diǎn)
 ? ? ? ?current = current->next;
 ? ? ? ?count++;
 ?  }
 ? ?if (current == NULL) {
 ? ? ? ?printf("Invalid position\n");
 ? ? ? ?return;
 ?  }
 ? ?current->prev->next = current->next;
 ? ?if (current->next != NULL) {
 ? ? ? ?current->next->prev = current->prev;
 ?  }
 ? ?free(current);
}
?
// 修改指定位置的節(jié)點(diǎn)值
void modify(Node* head, int position, int data) {
 ? ?Node* current = head;
 ? ?int count = 0;
 ? ?while (count < position && current != NULL) { ? ?// 找到要修改的節(jié)點(diǎn)
 ? ? ? ?current = current->next;
 ? ? ? ?count++;
 ?  }
 ? ?if (current == NULL) {
 ? ? ? ?printf("Invalid position\n");
 ? ? ? ?return;
 ?  }
 ? ?current->data = data;
}
?
// 對(duì)鏈表進(jìn)行排序
void sort(Node** head) {
 ? ?if (*head == NULL) {
 ? ? ? ?printf("List is empty\n");
 ? ? ? ?return;
 ?  }
 ? ?Node* current = *head;
 ? ?Node* temp = NULL;
 ? ?int swapped;
 ? ?do {
 ? ? ? ?swapped = 0;
 ? ? ? ?current = *head;
 ? ? ? ?while (current->next != NULL) {
 ? ? ? ? ? ?if (current->data > current->next->data) {
 ? ? ? ? ? ? ? ?int tmp = current->data;
 ? ? ? ? ? ? ? ?current->data = current->next->data;
 ? ? ? ? ? ? ? ?current->next->data = tmp;
 ? ? ? ? ? ? ? ?swapped = 1;
 ? ? ? ? ?  }
 ? ? ? ? ? ?current = current->next;
 ? ? ?  }
 ? ? ? ?temp = current;
 ?  } while (swapped);
}
?
// 打印鏈表
void printList(Node* head) {
 ? ?if (head == NULL) {
 ? ? ? ?printf("List is empty\n");
 ? ? ? ?return;
 ?  }
 ? ?Node* current = head;
 ? ?while (current != NULL) {
 ? ? ? ?printf("%d ", current->data);
 ? ? ? ?current = current->next;
 ?  }
 ? ?printf("\n");
}
?
// 釋放鏈表內(nèi)存
void freeList(Node** head) {
 ? ?if (*head == NULL) {
 ? ? ? ?return;
 ?  }
 ? ?Node* current = *head;
 ? ?Node* next = NULL;
 ? ?while (current != NULL) {
 ? ? ? ?next = current->next;
 ? ? ? ?free(current);
 ? ? ? ?current = next;
 ?  }
 ? ?*head = NULL;
}
?
int main() {
 ? ?Node* head = NULL;
 ? ?append(&head, 5);
 ? ?append(&head, 3);
 ? ?prepend(&head, 9);
 ? ?insert(&head, 7, 1);
 ? ?removeAt(&head, 2);
 ? ?modify(head, 0, 2);
 ? ?sort(&head);
 ? ?printList(head);
 ? ?freeList(&head);
 ? ?return 0;
}

代碼里實(shí)現(xiàn)了創(chuàng)建雙向鏈表、在鏈表末尾添加節(jié)點(diǎn)、在鏈表頭部添加節(jié)點(diǎn)、在指定位置插入節(jié)點(diǎn)、刪除指定位置的節(jié)點(diǎn)、修改指定位置的節(jié)點(diǎn)值、對(duì)鏈表進(jìn)行排序、打印鏈表及釋放鏈表內(nèi)存等功能。

三、思路講解

代碼里定義了一個(gè)雙向鏈表節(jié)點(diǎn)結(jié)構(gòu),包含數(shù)據(jù)域(data)、指向前一個(gè)節(jié)點(diǎn)的指針(prev)和指向后一個(gè)節(jié)點(diǎn)的指針(next)。

typedef struct Node {
 ? ?int data;
 ? ?struct Node* prev;
 ? ?struct Node* next;
} Node;

(1)createNode函數(shù)用于創(chuàng)建新節(jié)點(diǎn)。分配內(nèi)存以存儲(chǔ)節(jié)點(diǎn),并檢查內(nèi)存分配是否成功。設(shè)置節(jié)點(diǎn)的數(shù)據(jù)域?yàn)閭魅氲臄?shù)據(jù),并將前一個(gè)節(jié)點(diǎn)和后一個(gè)節(jié)點(diǎn)的指針都設(shè)置為NULL。最后,返回新創(chuàng)建的節(jié)點(diǎn)的指針。

(2)append函數(shù)用于在鏈表末尾添加節(jié)點(diǎn)。首先調(diào)用createNode函數(shù)創(chuàng)建一個(gè)新節(jié)點(diǎn)。如果頭節(jié)點(diǎn)為空,則將新節(jié)點(diǎn)設(shè)置為頭節(jié)點(diǎn)。否則,遍歷鏈表直到找到最后一個(gè)節(jié)點(diǎn),將新節(jié)點(diǎn)連接到最后一個(gè)節(jié)點(diǎn)的下一個(gè)位置,并設(shè)置新節(jié)點(diǎn)的prev指針指向最后一個(gè)節(jié)點(diǎn)。

(3)prepend函數(shù)用于在鏈表頭部添加節(jié)點(diǎn)。首先,調(diào)用createNode函數(shù)創(chuàng)建一個(gè)新節(jié)點(diǎn)。如果頭節(jié)點(diǎn)為空,則將新節(jié)點(diǎn)設(shè)置為頭節(jié)點(diǎn)。否則,將新節(jié)點(diǎn)的next指針指向當(dāng)前的頭節(jié)點(diǎn),將當(dāng)前頭節(jié)點(diǎn)的prev指針指向新節(jié)點(diǎn),然后將新節(jié)點(diǎn)設(shè)置為頭節(jié)點(diǎn)。

(4)insert函數(shù)用于在指定位置插入節(jié)點(diǎn)。首先,檢查插入位置是否合法。如果插入位置為0,則調(diào)用prepend函數(shù)在鏈表頭部插入節(jié)點(diǎn)。否則,調(diào)用createNode函數(shù)創(chuàng)建一個(gè)新節(jié)點(diǎn),然后遍歷鏈表直到找到插入位置前一個(gè)節(jié)點(diǎn),將新節(jié)點(diǎn)插入到這兩個(gè)節(jié)點(diǎn)之間,即將新節(jié)點(diǎn)的next指針指向前一個(gè)節(jié)點(diǎn)的next指針?biāo)赶虻墓?jié)點(diǎn),將新節(jié)點(diǎn)的prev指針指向前一個(gè)節(jié)點(diǎn),然后更新新節(jié)點(diǎn)兩側(cè)節(jié)點(diǎn)的指針。

(5)removeAt函數(shù)用于刪除指定位置的節(jié)點(diǎn)。首先,檢查鏈表是否為空。如果鏈表為空,則輸出相應(yīng)的提示信息。如果要?jiǎng)h除的位置為0,即刪除頭節(jié)點(diǎn),需要特殊處理,即將頭節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)設(shè)置為新的頭節(jié)點(diǎn),并將新的頭節(jié)點(diǎn)的prev指針設(shè)置為NULL。否則,遍歷鏈表直到找到要?jiǎng)h除的節(jié)點(diǎn),將要?jiǎng)h除節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)的next指針指向要?jiǎng)h除節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn),然后更新兩側(cè)節(jié)點(diǎn)的指針。

(6)modify函數(shù)用于修改指定位置的節(jié)點(diǎn)值。首先,遍歷鏈表直到找到要修改的節(jié)點(diǎn),然后將該節(jié)點(diǎn)的數(shù)據(jù)域設(shè)置為傳入的新數(shù)據(jù)。

(7)sort函數(shù)用于對(duì)鏈表進(jìn)行排序。首先,檢查鏈表是否為空。如果鏈表為空,則輸出相應(yīng)的提示信息。使用冒泡排序算法,重復(fù)遍歷鏈表并比較相鄰節(jié)點(diǎn)的值,如果前一個(gè)節(jié)點(diǎn)的值大于后一個(gè)節(jié)點(diǎn)的值,則交換它們的值。重復(fù)此過程,直到鏈表沒有發(fā)生交換為止。

(8)printList函數(shù)用于打印鏈表中的所有節(jié)點(diǎn)的值。首先,檢查鏈表是否為空。如果鏈表為空,則輸出相應(yīng)的提示信息。遍歷鏈表的每個(gè)節(jié)點(diǎn),并輸出節(jié)點(diǎn)中存儲(chǔ)的數(shù)據(jù)。

(9)freeList函數(shù)用于釋放鏈表的內(nèi)存。首先,檢查鏈表是否為空。如果鏈表為空,則直接返回。遍歷鏈表的每個(gè)節(jié)點(diǎn),使用free函數(shù)釋放節(jié)點(diǎn)的內(nèi)存,并將節(jié)點(diǎn)指針設(shè)為NULL,最后將頭節(jié)點(diǎn)指針設(shè)為NULL。

以上就是C語言實(shí)例之雙向鏈表增刪改查的詳細(xì)內(nèi)容,更多關(guān)于C語言雙向鏈表的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • VS2019中CMake項(xiàng)目如何指定c++語言標(biāo)準(zhǔn)

    VS2019中CMake項(xiàng)目如何指定c++語言標(biāo)準(zhǔn)

    這篇文章主要介紹了VS2019中CMake項(xiàng)目如何指定c++語言標(biāo)準(zhǔn),需要的朋友可以參考下
    2020-02-02
  • C語言開發(fā)實(shí)現(xiàn)貪吃蛇游戲

    C語言開發(fā)實(shí)現(xiàn)貪吃蛇游戲

    這篇文章主要為大家詳細(xì)介紹了C語言開發(fā)實(shí)現(xiàn)貪吃蛇游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-07-07
  • 一篇文章帶你了解C語言內(nèi)存對(duì)齊公式

    一篇文章帶你了解C語言內(nèi)存對(duì)齊公式

    這篇文章主要介紹了C語言內(nèi)存對(duì)齊,包括內(nèi)存對(duì)其的基本概念及用法,以及注意事項(xiàng),并以實(shí)例形式加以說明,需要的朋友可以參考下,希望能給你帶來幫助
    2021-08-08
  • C語言內(nèi)存函數(shù)的具體使用

    C語言內(nèi)存函數(shù)的具體使用

    本文介紹了C語言中幾個(gè)常用的內(nèi)存函數(shù),包括memcpy、memmove、memset、memcmp的使用方法及其模擬實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-11-11
  • 詳解C++中的const關(guān)鍵字及與C語言中const的區(qū)別

    詳解C++中的const關(guān)鍵字及與C語言中const的區(qū)別

    這篇文章主要介紹了C++中的const關(guān)鍵字及與C語言中const的區(qū)別,const將所修飾的變量對(duì)象轉(zhuǎn)化為常量,需要的朋友可以參考下
    2016-04-04
  • C語言實(shí)現(xiàn)訪問及查詢MySQL數(shù)據(jù)庫的方法

    C語言實(shí)現(xiàn)訪問及查詢MySQL數(shù)據(jù)庫的方法

    這篇文章主要介紹了C語言實(shí)現(xiàn)訪問及查詢MySQL數(shù)據(jù)庫的方法,涉及C語言基于libmysql.lib實(shí)現(xiàn)訪問MySQL數(shù)據(jù)庫的相關(guān)操作技巧,需要的朋友可以參考下
    2018-01-01
  • c語言中abs()和fabs()的區(qū)別點(diǎn)整理

    c語言中abs()和fabs()的區(qū)別點(diǎn)整理

    在本篇文章里小編給大家分享的是關(guān)于c語言abs()和fabs()的區(qū)別,有需要的朋友們可以參考學(xué)習(xí)下。
    2020-02-02
  • 詳解C++右值引用

    詳解C++右值引用

    很多初學(xué)者都感覺右值引用晦澀難懂,其實(shí)不然。右值引用只不過是一種新的 C++ 語法,真正理解起來有難度的是基于右值引用引申出的2種 C++ 編程技巧,分別為移動(dòng)語義和完美轉(zhuǎn)發(fā)。本節(jié)給讀者講解什么是右值引用以及它的基本用法。
    2021-06-06
  • C語言實(shí)現(xiàn)多線程定時(shí)器實(shí)例講解

    C語言實(shí)現(xiàn)多線程定時(shí)器實(shí)例講解

    在本篇文章里小編給各位分享的是一篇關(guān)于C語言實(shí)現(xiàn)多線程定時(shí)器實(shí)例講解內(nèi)容,有需要的朋友們可以參考學(xué)習(xí)下。
    2021-01-01
  • C++中內(nèi)存分區(qū)及其作用分析

    C++中內(nèi)存分區(qū)及其作用分析

    C++內(nèi)存分區(qū)包括棧區(qū)、堆區(qū)、全局靜態(tài)區(qū)、常量區(qū),各自負(fù)責(zé)不同的數(shù)據(jù)存儲(chǔ)和回收,棧區(qū)主要用于存放函數(shù)局部變量和參數(shù),堆區(qū)用于動(dòng)態(tài)分配內(nèi)存,全局靜態(tài)區(qū)用于存放全局靜態(tài)變量和靜態(tài)成員變量,常量區(qū)用于存放常量和字符串常量
    2023-04-04

最新評(píng)論