目录
一.双链表的定义
二.要实现的功能
三.功能实现
0、创建结点
1、初始化
2、打印
3、尾插
4、尾删
5、头插
6、头删
7、任意插入
8、任意删除
9、查找
四.全部代码的实现
1、text.c
2、List.c
3、List.h
由图这就是一个双链表,可以看出它是一个由尾和头双向指向的环,且每个结点之间都是双向指向的。
双链表是一种数据结构,所谓数据结构就是用来储存数据的工具,功能大致就和基本储存数据的数组或单链表相类似。无非就是:
初始化、打印、尾插、尾删、头插、头删、任意插入、任意删除、查找、更改。这些基本的数据操作。
即创建一个新的双链表结点,由于不知道应该连接在什么地方,所以且先让它指向NULL。在将需要的数据放在新的结点中,这样新链表的初始化就好了
//创建结点 ListNode* BuyListNode(ListDateType x) { ListNode* node = (ListNode*)malloc(sizeof(ListNode)); if (node == NULL) { exit(-1); } node->next = NULL; node->prev = NULL; node->date = x; return node; }
即创建一个空的双链表,由双链表的特新,双向指向,我们需要创建一个由中间指向自己的哨兵位的头结点,不存放有效的数据
//初始化 ListNode* ListInit() { ListNode* phead = BuyListNode(0); phead->next = phead; phead->prev = phead; return phead; }
打印需要遍历一遍链表,所以要用到循环,那么就需要结束条件,由下图可以看出,头和尾是相连的,所以循环结束的的条件就是当访问的下一个结点是头结点时就停止
//打印 void ListPrint(ListNode* phead) { assert(phead); ListNode* cur = phead->next; while (cur != phead) { printf("%d ", cur->date); cur = cur->next; } printf("\n"); }
先创建一个新的结点,再将其与tail尾结点连接起来即可,因为双链表的特性,所以可以直接由头结点得到尾结点,而不需要去遍历一遍链表,时间复杂度就直线降低为o(1)了
//尾插 void ListPushBack(ListNode* phead, ListDateType x) { assert(phead); ListNode* newnode = BuyListNode(x); ListNode* tail = phead->prev; tail->next = newnode; newnode->prev = tail; newnode->next = phead; phead->prev = newnode; //ListInsert(phead, x);//可以用任意插入简化简化 }
尾删只需要记录tail尾结点的前一个结点即可,将头节点与尾结点连接起来后,再进行tail结点的删除
//尾删 void ListPopBack(ListNode* phead) { assert(phead); assert(phead->next != NULL); ListNode* tailprev = phead->prev->prev; ListNode* tail = phead->prev; free(tail); tail = NULL; tailprev->next = phead; phead->prev = tailprev; //ListErase(phead->prev);//用任意删除简化 }
因为双链表有一个哨兵位的头结点,所以头插就相当于是在phead头结点和frist第一个结点中间插入一个结点,可以先记录第一个结点,在将新的结点与头结点连接起来后,再将新结点与第一个结点连接起来
void ListPushFront(ListNode* phead, ListDateType x) { assert(phead); ListNode* newnode = BuyListNode(x); ListNode* frist = phead->next; phead->next = newnode; newnode->prev = phead; newnode->next = frist; frist->prev = newnode; //ListInsert(phead->next, x);//用任意插入简化 }
头删就像相当于在头结点与第一个结点之间删除一个结点,记录第一个结点,将头节点与第二个结点删除后,再q第一个结点。
//头删 void ListPopFront(ListNode* phead) { assert(phead); assert(phead->next != phead); ListNode* frist = phead->next; ListNode* second = frist->next; phead->next = second; second->prev = phead; free(frist); frist = NULL; //ListErase(phead->next);用任意删除简化 }
对双链表来说就是两个结点之间的插入,因为每一个链表旁边一定有两个结点(环结构)。
首先先遍历一遍链表找到这个待插入处的结点,然后记录待插入结点处的前一个结点,再将新结点连接这个记录的结点,然后再连接待插入结点处的结点。
//任意结点插入 void ListInsert(ListNode* pos, ListDateType x) { assert(pos); ListNode* newNode = BuyListNode(x); ListNode* posPrev = pos->prev; newNode->prev = posPrev; posPrev->next = newNode; pos->prev = newNode; newNode->next = pos; }
任意的删除在单链表中我们分了好几种情况,单在双链表中我们只需要按正常的情况考虑即可,因为它没有NULL指向这种非法访问空间机会。
删除时需要记录待删除结点pos前和后的结点,在将前后两个结点连接后再进行pos结点的删除
//任意结点的删除 void ListErase(ListNode* pos) { assert(pos); ListNode* posPrev = pos->prev; ListNode* posNext = pos->next; posPrev->next = posNext; posNext->prev = posPrev; free(pos); pos = NULL; }
遍历链表对比数据,找到值返回那个结点就行了
//查找 ListNode* ListFind(ListNode* phead, ListDateType x) { assert(phead); assert(phead->next != NULL); ListNode* cur = phead->next; while (cur != phead) { if (cur->date == x) { return cur; } else { cur = cur->next; } } printf("找不到\n"); return NULL; }
#define _CRT_SECURE_NO_WARNINGS 1 #include "List.h" void ListText() { ListNode* phead = NULL; phead = ListInit(); ListPushBack(phead,1); ListPushBack(phead,2); ListPushBack(phead,3); ListPrint(phead); ListPopBack(phead); ListPrint(phead); ListPushFront(phead, 99); ListPrint(phead); ListPopFront(phead); ListPrint(phead); } void ListText1() { ListNode* phead = ListInit(); ListPushBack(phead, 1); ListPushBack(phead, 2); ListPushBack(phead, 3); ListPushBack(phead, 4); ListPushBack(phead, 5); ListNode* pos = ListFind(phead, 3); ListInsert(pos, 99); ListErase(pos); ListPrint(phead); ListDestory(&phead); } int main() { //ListText(); ListText1(); return 0; }
#define _CRT_SECURE_NO_WARNINGS 1 #include "List.h" //创建结点 ListNode* BuyListNode(ListDateType x) { ListNode* node = (ListNode*)malloc(sizeof(ListNode)); if (node == NULL) { exit(-1); } node->next = NULL; node->prev = NULL; node->date = x; return node; } //初始化 ListNode* ListInit() { ListNode* phead = BuyListNode(0); phead->next = phead; phead->prev = phead; return phead; } //清理 void ListClear(ListNode* phead) { assert(phead); //清理全部数据,保留头结点 ListNode* cur = phead->next; while (cur != phead) { ListNode* next = cur->next; free(cur); cur = NULL; cur = next; } } //销毁 void ListDestory(ListNode** pphead) { assert(*pphead); ListClear(*pphead); free(*pphead); *pphead = NULL; } //打印 void ListPrint(ListNode* phead) { assert(phead); ListNode* cur = phead->next; while (cur != phead) { printf("%d ", cur->date); cur = cur->next; } printf("\n"); } //尾插 void ListPushBack(ListNode* phead, ListDateType x) { /*assert(phead); ListNode* newnode = BuyListNode(x); ListNode* tail = phead->prev; tail->next = newnode; newnode->prev = tail; newnode->next = phead; phead->prev = newnode;*/ ListInsert(phead, x); } //尾删 void ListPopBack(ListNode* phead) { /*assert(phead); assert(phead->next != NULL); ListNode* tailprev = phead->prev->prev; ListNode* tail = phead->prev; free(tail); tail = NULL; tailprev->next = phead; phead->prev = tailprev;*/ ListErase(phead->prev); } //头插 void ListPushFront(ListNode* phead, ListDateType x) { /*assert(phead); ListNode* newnode = BuyListNode(x); ListNode* frist = phead->next; phead->next = newnode; newnode->prev = phead; newnode->next = frist; frist->prev = newnode;*/ ListInsert(phead->next, x); } //头删 void ListPopFront(ListNode* phead) { /*assert(phead); assert(phead->next != phead); ListNode* frist = phead->next; ListNode* second = frist->next; phead->next = second; second->prev = phead; free(frist); frist = NULL;*/ ListErase(phead->next); } //查找 ListNode* ListFind(ListNode* phead, ListDateType x) { assert(phead); assert(phead->next != NULL); ListNode* cur = phead->next; while (cur != phead) { if (cur->date == x) { return cur; } else { cur = cur->next; } } printf("找不到\n"); return NULL; } //任意结点插入 void ListInsert(ListNode* pos, ListDateType x) { assert(pos); ListNode* newNode = BuyListNode(x); ListNode* posPrev = pos->prev; newNode->prev = posPrev; posPrev->next = newNode; pos->prev = newNode; newNode->next = pos; } //任意结点的删除 void ListErase(ListNode* pos) { assert(pos); ListNode* posPrev = pos->prev; ListNode* posNext = pos->next; posPrev->next = posNext; posNext->prev = posPrev; free(pos); pos = NULL; }
#pragma once #include
#include #include typedef int ListDateType; //双向链表 typedef struct ListNode { struct ListNode* next; struct ListNode* prev; ListDateType date; }ListNode; //初始化 ListNode* ListInit(); //销毁 void ListDestory(ListNode** pphead); //清理 void ListClear(ListNode* phead); //打印 void ListPrint(ListNode* phead); //尾插 void ListPushBack(ListNode* phead, ListDateType x); //尾删 void ListPopBack(ListNode* phead); //头插 void ListPushFront(ListNode* phead, ListDateType x); //头删 void ListPopFront(ListNode* phead); //查找 ListNode* ListFind(ListNode* phead, ListDateType x); //任意结点插入 void ListInsert(ListNode* pos, ListDateType x); //任意结点的删除 void ListErase(ListNode* pos);