欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 养生 > 【数据结构】链表

【数据结构】链表

2024/10/24 20:23:27 来源:https://blog.csdn.net/2302_81171591/article/details/141355816  浏览:    关键词:【数据结构】链表

目录

1.链表的概念及结构

 2.单链表的实现

 2.1 SLTPrint()打印链表

2.2 SLTBuyNode() 申请空间

2.3  SLTPushBack() 尾插

2.4  SLTPushFront()  头插

 2.5 SSLTPopBack() 尾删

 2.6 SLTInesert()  在指定位置之前插入

2.7 SLTInsertAfter() 在指定位置之后插入

 2.8 SLTErase() 删除pos节点

 2.9 SLTEraseAfter() 删除pos之后的一个节点

2.10 SListDesTroy()销毁链表

3.完整代码

4.双向链表

5. 双向链表的实现

5.1 LTBuyNode() 申请节点

5.2     LTInit() 初始化

5.3 LTPushBack()   尾插

5.4 LTPrint()打印

5.5 LTPushFront ()   头插

5.6  LTPopBack()  尾删

5.7  LTPopFront () 头删

5.8 LTFind () 查找

5.9 LTInsert() 在pos之后插入一个数据

5.10    LTErase()  删除指定位置的节点

5.11  LTDesTroy() 销毁链表

5.12 LTDesTroy()  销毁链表

6.完整代码


1.链表的概念及结构


概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。

 链表是线性表的一种,物理结构不一定是线性的,逻辑结构一定是线性的

b66f882c909140258d525d98d8dbfcd2.png

链表的结构跟火车车厢相似,淡季的时候车次的车厢会相应减少,旺季的时候车次的车厢会额外增加几节,只需将火车里的某节车厢去掉/加上,不影响其他车厢,每节都是相互独立的。

车厢是独立存在的,且每节车厢都有车门。想象一下这样的场景,假设每节车厢的车门都是锁上的状态,需要不同的钥匙才能解锁,每次只能带一把钥匙的情况下怎么才能从车头走向车尾?

在链表里,每节“车厢”是什么样的呢?

 cf94a67271fa4eef95c13e081f2a34ac.png

与顺序表不同的是,链表里的每节“车厢”都是独立申请下来的空间,我们称之为“节点/结点”

节点的组成主要有两部分:当前节点要保存的数据和保存下一个节点的地址(指针变量)。

图中指针变量pList保存的是第一个节点的地址,我们称pList此时“指向”第一个节点,如果我们希望pList“指向”第二个节点时,只需修改pList保存的内容为0x0012FFA0.

为什么还需要指针变量来保存下⼀个节点的位置?
链表中每个节点都是独⽴申请的(即需要插⼊数据时才去申请⼀块节点的空间),我们需要通过指针变量来保存下⼀个节点位置才能从当前节点找到下⼀个节点。
结合前⾯学到的结构体知识,我们可以给出每个节点对应的结构体代码:
假设当前保存的节点为整型

struct SListNode
{
int data;
//节点数据
struct SListNode* next; //指针变量⽤保存下⼀个节点的地址
};

当我们想要保存⼀个整型数据时,实际是向操作系统申请了⼀块内存,这个内存不仅要保存整型数
据,也需要保存下⼀个节点的地址(当下⼀个节点为空时保存的地址为空)。
当我们想要从第⼀个节点⾛到最后⼀个节点时,只需要在前⼀个节点拿上下⼀个节点的地址(下⼀个节点的钥匙)就可以了。

链表的分类
实际中链表的结构非常多样,以下情况组合起来就有8种链表结构:
1. 单向或者双向

               f62753d58d0c4f61bea26cef3ee2175c.png

 2. 带头或者不带头

               9f44f2b0e6ed4e308c5e79ec3219c00f.png

3. 循环或者非循环

              3b269a9749584de9ac6bd46e7540652c.png

虽然有这么多的链表的结构,但是我们实际中最常用还是两种结构:

72b167387cb9465289ae5a5a4e36c009.png

 1. 无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多。
2. 带头双向循环链表:结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向
循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带来很多优势,实现反而简单了,后面我们代码实现了就知道了。

 2.单链表的实现

链表实现大纲

typedef int SLTDataType;
typedef struct SListNode
{
SLTDataType data;
//节点数据
struct SListNode* next; //指针保存下⼀个节点的地址
}SLTNode;void SLTPrint(SLTNode* phead);
//头部插⼊删除/尾部插⼊删除
void SLTPushBack(SLTNode** pphead, SLTDataType x);
void SLTPushFront(SLTNode** pphead, SLTDataType x);
void SLTPopBack(SLTNode** pphead);
void SLTPopFront(SLTNode** pphead);
//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x);
//在指定位置之前插⼊数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos);
//在指定位置之后插⼊数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x);
//删除pos之后的节点
void SLTEraseAfter(SLTNode* pos);
//销毁链表
void SListDesTroy(SLTNode** pphead);

 2.1 SLTPrint()打印链表

将节点连接起来

void text()
{   //链表是由一个一个的节点组成//创建几个节点SLTNode* node1 = (SLTNode*)malloc(sizeof(SLTNode));node1->data = 1;SLTNode* node2 = (SLTNode*)malloc(sizeof(SLTNode));node2->data = 2;SLTNode * node3 = (SLTNode*)malloc(sizeof(SLTNode));node3->data = 3;SLTNode* node4 = (SLTNode*)malloc(sizeof(SLTNode));node4->data = 4;//将四个节点链接起来node1->next = node2;node2->next = node3;node3->next = node4;node4->next = NULL;//调用链表的打印SLTNode* plist = node1;SLTPrint( plist);
}

c5be55d56a484e138edeabbd9cca7c74.jpeg

 SLTprint实现

void SLTPrint(SLTNode* phead)
{SLTNode* pcur = phead;while (pcur){printf("%d->", pcur->data);pcur = pcur->next;}printf("NULL");printf("\n");
}

 打印效果

5f7ef83029634467af4ddf7707a5eeb6.png

2.2 SLTBuyNode() 申请空间

由于申请空间很频繁,所以直接封装成了函数以便调用

//申请空间
SLTNode* SLTBuyNode(SLTDataType x)
{//申请节点SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));if (newnode == NULL){perror("malloc fail!");exit(1);}newnode->data = x;newnode->next = NULL;//返回节点return newnode;
}

2.3  SLTPushBack() 尾插

//尾插void SLTPushBack(SLTNode** phead, SLTDataType x)
{   assert(pphead);SLTNode* newnode=SLTBuyNode(x);//空链表和非空链表if (*phead == NULL){*phead = newnode;}else{
SLTNode* pcur = *phead;//找尾while (pcur->next){pcur = pcur->next;}//链接节点pcur->next = newnode;}}

测试一下

 void text2()
{SLTNode* plist = NULL;SLTPrint(plist);SLTPushBack(&plist, 1);SLTPushBack(&plist, 2);SLTPushBack(&plist, 3);SLTPrint(plist);
}

 效果预期,实现完成4f4f21fd27eb477ead9d6e74d0fc705f.png

2.4  SLTPushFront()  头插

void SLTPushFront(SLTNode** pphead, SLTDataType x){assert(pphead);SLTNode* newnode = SLTBuyNode(x);newnode->next =*pphead;*pphead= newnode;}

 测试一下

void text3()
{SLTNode* plist = NULL;SLTPrint(plist);SLTPushFront(&plist, 3);SLTPushFront(&plist, 2);SLTPushFront(&plist, 1);SLTPrint(plist);
}

测试结果

a9e58ac19ef7457c9ddfa92b0bfaea7d.png

 2.5 SSLTPopBack() 尾删

//尾删
void SLTPopBack( SLTNode** pphead)
{assert(pphead&&*pphead);//只有一个节点if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;}else //有多个节点{SLTNode* prev = *pphead;SLTNode* ptail = *pphead;while (ptail->next){prev = ptail;ptail = ptail->next;}prev->next = NULL;}
}

测试

void text4()
{SLTNode* plist = NULL;SLTPushFront(&plist, 3);SLTPushFront(&plist, 2);SLTPushFront(&plist, 1);SLTPrint(plist);SLTPopBack(&plist);SLTPrint(plist);SLTPopBack(&plist);SLTPrint(plist);SLTPopBack(&plist);SLTPrint(plist);SLTPopBack(&plist);
}

 效果

3b8f8aba45ce4e2a835b31512a9ebaee.png

 2.6 SLTPopFront()   头删

//头删void SLTPopFront(SLTNode** pphead){assert(pphead&&*pphead);SLTNode* node = (*pphead)->next;free(*pphead);*pphead = node;}

 测试1

 void text5(){SLTNode* plist = NULL;SLTPushFront(&plist, 3);SLTPushFront(&plist, 2);SLTPushFront(&plist, 1);SLTPrint(plist);SLTPopFront(&plist);SLTPrint(plist);SLTPopFront(&plist);SLTPrint(plist);SLTPopFront(&plist);SLTPrint(plist);}

 46a189531a87457e8ffded87729ae025.png

 2.6  SLTFind() 查找

 //查找SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{SLTNode* find = phead;while (find){if (find->data == x){return find;}find = find->next;}return NULL;}

测试

void text5()
{SLTNode* plist = NULL;SLTPushFront(&plist, 3);SLTPushFront(&plist, 2);SLTPushFront(&plist, 1);SLTPrint(plist);if (SLTFind(plist, 1)){printf("找到了\n");
}else{printf("没找到\n");}if (SLTFind(plist, 1)){printf("找到了\n");}else{printf("没找到\n");}if (SLTFind(plist, 5)){printf("找到了\n");}else{printf("没找到\n");}
}

2b4486dc291c40c7a4c6ba294a570549.png

 2.6 SLTInesert()  在指定位置之前插入

//在指定位置之前插入
void SLTInsert(SLTNode** pphead,SLTNode* pos,SLTDataType x)
{assert(pphead && *pphead);assert(pos);SLTNode* newnode= SLTBuyNode(x);if (pos == *pphead){SLTPushFront(pphead, x);}else {SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}newnode->next = pos;prev->next = newnode;}
}
 void text6(){SLTNode* plist = NULL;SLTPushFront(&plist, 3);SLTPushFront(&plist, 2);SLTPushFront(&plist, 1);SLTPrint(plist);SLTNode* find = SLTFind(plist,3);SLTInsert(&plist, find, 11);SLTPrint(plist);}

 7f539055cf9941918bf00657cba5f6c5.png

2.7 SLTInsertAfter() 在指定位置之后插入

//在指定位置之后插入
void SLTInsertAfter(SLTNode* pos,SLTDataType x)
{assert(pos);SLTNode* newnode = SLTBuyNode(x);newnode->next = pos->next;pos->next = newnode;}
 void text7(){SLTNode* plist = NULL;SLTPushFront(&plist, 3);SLTPushFront(&plist, 2);SLTPushFront(&plist, 1);SLTPrint(plist);//在2后面插入11SLTNode* find = SLTFind(plist, 2);SLTInsertAfter(find, 11);SLTPrint(plist);}

410b99f16a104106849f85613794f08f.png

 2.8 SLTErase() 删除pos节点

 //删除pos节点void SLTErase( SLTNode** pphead,SLTNode* pos){assert(pphead && *pphead);assert(pos);if (pos == *pphead){SLTPopFront(pphead);}else{SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}prev->next = pos->next;free(pos);}}

void text7(){SLTNode* plist = NULL;SLTPushFront(&plist, 3);SLTPushFront(&plist, 2);SLTPushFront(&plist, 1);SLTPrint(plist);SLTErase(&plist, SLTFind(plist, 1));SLTPrint(plist);}

03a58732ca4b44309a8987075dba0eb2.png

 2.9 SLTEraseAfter() 删除pos之后的一个节点

 //删除pos之后的节点void SLTEraseAfter(SLTNode* pos){assert(pos && pos->next);SLTNode* del = pos->next;//pos  del pos->next->nextpos->next= pos->next->next;free(del);}
void text7()
{SLTNode* plist = NULL;SLTPushFront(&plist, 3);SLTPushFront(&plist, 2);SLTPushFront(&plist, 1);SLTPrint(plist);SLTEraseAfter( SLTFind(plist, 2));SLTPrint(plist);
}

 fa976084cd8542f48d31e6506f2df430.png

2.10 SListDesTroy()销毁链表

 //销毁链表void SListDesTroy(SLTNode** pphead){SLTNode* pcur = *pphead;while (pcur){SLTNode* next = pcur->next;free(pcur);pcur = next;}*pphead = NULL;}

3.完整代码

Slist.h

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLTDataType;//一键替换
typedef struct SListNode
{SLTDataType data;//节点数据struct SListNode* next; //指针保存下⼀个节点的地址
}SLTNode;
void SLTPrint(SLTNode* phead);
//头部插⼊删除/尾部插⼊删除
void SLTPushBack(SLTNode** pphead, SLTDataType x);
void SLTPushFront(SLTNode** pphead, SLTDataType x);
void SLTPopBack(SLTNode** pphead);
void SLTPopFront(SLTNode** pphead);
//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x);
//在指定位置之前插⼊数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos);
//在指定位置之后插⼊数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x);
//删除pos之后的节点
void SLTEraseAfter(SLTNode* pos);
//销毁链表
void SListDesTroy(SLTNode** pphead);

Slist.c

#include"Slist.h"
//打印链表
void SLTPrint(SLTNode* phead)
{SLTNode* pcur = phead;while (pcur){printf("%d->", pcur->data);pcur = pcur->next;}printf("NULL");printf("\n");
}//申请空间SLTNode* SLTBuyNode(SLTDataType x)
{//申请节点SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));if (newnode == NULL){perror("malloc fail!");exit(1);}newnode->data = x;newnode->next = NULL;//返回节点return newnode;
}//尾插void SLTPushBack(SLTNode** phead, SLTDataType x)
{   SLTNode* newnode=SLTBuyNode(x);//空链表和非空链表if (*phead == NULL){*phead = newnode;}else{
SLTNode* pcur = *phead;//找尾while (pcur->next){pcur = pcur->next;}//链接节点pcur->next = newnode;}}//头插void SLTPushFront(SLTNode** pphead, SLTDataType x){assert(pphead);SLTNode* newnode = SLTBuyNode(x);newnode->next =*pphead;*pphead= newnode;}//尾删void SLTPopBack( SLTNode** pphead){assert(pphead&&*pphead);//只有一个节点if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;}else //有多个节点{SLTNode* prev = *pphead;SLTNode* ptail = *pphead;while (ptail->next){prev = ptail;ptail = ptail->next;}prev->next = NULL;}}//头删void SLTPopFront(SLTNode** pphead){assert(pphead&&*pphead);SLTNode* node = (*pphead)->next;free(*pphead);*pphead = node;}//查找SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{SLTNode* find = phead;while (find){if (find->data == x){return find;}find = find->next;}return NULL;}//在指定位置之前插入void SLTInsert(SLTNode** pphead,SLTNode* pos,SLTDataType x){assert(pphead && *pphead);assert(pos);SLTNode* newnode= SLTBuyNode(x);if (pos == *pphead){SLTPushFront(pphead, x);}else {SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}newnode->next = pos;prev->next = newnode;}}//在指定位置之后插入void SLTInsertAfter(SLTNode* pos,SLTDataType x){assert(pos);SLTNode* newnode = SLTBuyNode(x);newnode->next = pos->next;pos->next = newnode;}//删除pos节点void SLTErase( SLTNode** pphead,SLTNode* pos){assert(pphead && *pphead);assert(pos);if (pos == *pphead){SLTPopFront(pphead);}else{SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}prev->next = pos->next;free(pos);}}//删除pos之后的节点void SLTEraseAfter(SLTNode* pos){assert(pos && pos->next);SLTNode* del = pos->next;//pos  del pos->next->nextpos->next= pos->next->next;free(del);}//销毁链表void SListDesTroy(SLTNode** pphead){SLTNode* pcur = *pphead;while (pcur){SLTNode* next = pcur->next;free(pcur);pcur = next;}*pphead = NULL;}

4.双向链表

1. 双向链表的结构

2de429c0fe9e48dbbb338e22735e40f8.png

注意:这⾥的“带头”跟前⾯我们说的“头节点”是两个概念,实际前⾯的在单链表阶段称呼不严
谨,但是为了同学们更好的理解就直接称为单链表的头节点。
带头链表⾥的头节点,实际为“哨兵位”,哨兵位节点不存储任何有效元素,只是站在这⾥“放哨
的”

“哨兵位”存在的意义:遍历循环链表避免死循环

5. 双向链表的实现

typedef int LTDataType;
typedef struct ListNode
{
struct ListNode* next; //指针保存下⼀个节点的地址
struct ListNode* prev; //指针保存前⼀个节点的地址
LTDataType data;
}LTNode;//void LTInit(LTNode** pphead);
LTNode* LTInit();
void LTDestroy(LTNode* phead);
void LTPrint(LTNode* phead);
bool LTEmpty(LTNode* phead);
void LTPushBack(LTNode* phead, LTDataType x);
void LTPopBack(LTNode* phead);
void LTPushFront(LTNode* phead, LTDataType x);
void LTPopFront(LTNode* phead);
//在pos位置之后插⼊数据
void LTInsert(LTNode* pos, LTDataType x);
void LTErase(LTNode* pos);
LTNode *LTFind(LTNode* phead,LTDataType x);

5.1 LTBuyNode() 申请节点

//申请节点
LTNode* LTBuyNode(LTDataType x)
{LTNode* node = (LTNode*)malloc(sizeof(LTNode));if (node == NULL){perror("malloc fail!");exit(1);}node->next = node->prev = node;return node;
}

5.2     LTInit() 初始化

//初始化
void LTInit(LTNode** pphead)
{//给链表创建一个哨兵位*pphead = LTBuyNode(-1);
}

5.3 LTPushBack()   尾插

//尾插
void LTPushBack(LTNode* pphead, LTDataType x)
{assert(pphead);LTNode* newnode=LTBuyNode(x);//pphead          pphead->prev             newnodenewnode->next = pphead;newnode->prev = pphead->prev;pphead->prev->next = newnode;pphead->prev = newnode;}

5.4 LTPrint()打印

//打印
void LTPrint(LTNode* phead)
{ListNode* pcur = phead;while (pcur != phead){printf("%d->", pcur->data);pcur = pcur->next;}printf("\n");
}

5.5 LTPushFront ()   头插

//头插
void LTPushFront(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode= LTBuyNode(x);//phead   newnode phead->nextnewnode->next = phead->next;newnode->prev = phead;phead->next->prev = newnode;phead->next = newnode;}

5.6  LTPopBack()  尾删

//尾删
void LTPopBack(LTNode* phead)
{//链表必须有效且链表不能为空assert(phead&&phead->next!=phead);LTNode* del = phead->prev;//phead  phead->prev->prev   phead->prevdel->prev->next = phead;phead->prev = del->prev;//删除delfree(del);del = NULL;
}

5.7  LTPopFront () 头删

//头删
void LTPopFront(LTNode* phead)
{//链表必须有效且链表不能为空assert(phead && phead->next != phead);//phead  del del->nextLTNode* del = phead->next;//删除delphead->next=del->next;free(del);del = NULL;
}

5.8 LTFind () 查找

//查找
LTNode* LTFind(LTNode* phead, LTDataType x)
{assert(phead && phead->next != phead);LTNode* find = phead->next;while (find!=phead){if (find->data == x){return find;}find = find->next;}return NULL;
}

5.9 LTInsert() 在pos之后插入一个数据

//在pos之后插入数据
void LTInsert(LTNode* pos, LTDataType x)
{assert(pos && pos->next != pos);LTNode* newnode = LTBuyNode(x);
//	pos   newnode  pos->nextnewnode->next = pos->next;newnode->prev = pos;pos->next->prev = newnode;pos->next = newnode;
}

5.10    LTErase()  删除指定位置的节点

//删除指定位置
void LTErase(LTNode* pos)
{assert(pos);LTNode* del = pos;// pos->prev  pos  pos->nextpos->prev->next = pos->next;pos->next->prev->prev;free(del);del = NULL;}

5.11  LTDesTroy() 销毁链表

//销毁链表
void LTDesTroy(LTNode* phead)
{assert(phead);LTNode* del = phead->next;LTNode* next = phead->next;while (next!=phead){free(del);del = next = next->next;}
free(phead);
phead=NULL;
}

5.12 LTDesTroy()  销毁链表

//销毁链表
void LTDesTroy(LTNode* phead)
{assert(phead);LTNode* del = phead->next;LTNode* next = phead->next;while (next!=phead){free(del);del = next = next->next;}free(phead);phead = NULL;}

顺序表和链表的区别

不同点顺序表链表(带头双向循环)
存储空间上物理上一定连续逻辑上连续,但物理上不一定连续
随机访问支持O(1)不支持O(N)
任意位置插入和删除可能需要搬移元素,效率低O(N)只需修改指针方向
插入动态顺序表,空间不够需要扩容没有容量的概念(按需申请)
应用场景元素高效存储+频繁访问任意位置插入和删除频繁
缓存和利用

6.完整代码

list.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>typedef int LTDataType;
typedef struct ListNode
{LTDataType data;struct ListNode* next;struct ListNode* prev;
}LTNode;//初始化
void LTInit( LTNode** pphead);
//尾插
void LTPushBack(LTNode* pphead,LTDataType x);
//打印
void LTPrint(LTNode* phead);
//头插
void LTPushFront(LTNode* phead, LTDataType x);
//尾删
void LTPopBack(LTNode* phead);
//头删
void LTPopFront(LTNode* phead);
//查找
LTNode* LTFind(LTNode* phead, LTDataType x);
//在pos之后插入数据
void LTInsert(LTNode* pos, LTDataType x);
//删除pos节点
void LTErase(LTNode* pos);
//销毁链表
void LTDesTroy(LTNode* phead);

list.c

#include"List.h"//申请节点
LTNode* LTBuyNode(LTDataType x)
{LTNode* node = (LTNode*)malloc(sizeof(LTNode));if (node == NULL){perror("malloc fail!");exit(1);}node->next = node->prev = node;return node;
}//初始化
void LTInit(LTNode** pphead)
{//给链表创建一个哨兵位*pphead = LTBuyNode(-1);
}
//尾插
void LTPushBack(LTNode* pphead, LTDataType x)
{assert(pphead);LTNode* newnode=LTBuyNode(x);//pphead          pphead->prev             newnodenewnode->next = pphead;newnode->prev = pphead->prev;pphead->prev->next = newnode;pphead->prev = newnode;}//打印
void LTPrint(LTNode* phead)
{ListNode* pcur = phead;while (pcur != phead){printf("%d->", pcur->data);pcur = pcur->next;}printf("\n");
}//头插
void LTPushFront(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode= LTBuyNode(x);//phead   newnode phead->nextnewnode->next = phead->next;newnode->prev = phead;phead->next->prev = newnode;phead->next = newnode;}//尾删
void LTPopBack(LTNode* phead)
{//链表必须有效且链表不能为空assert(phead&&phead->next!=phead);LTNode* del = phead->prev;//phead  phead->prev->prev   phead->prevdel->prev->next = phead;phead->prev = del->prev;//删除delfree(del);del = NULL;
}
//头删
void LTPopFront(LTNode* phead)
{//链表必须有效且链表不能为空assert(phead && phead->next != phead);//phead  del del->nextLTNode* del = phead->next;//删除delphead->next=del->next;free(del);del = NULL;
}
//查找
LTNode* LTFind(LTNode* phead, LTDataType x)
{assert(phead && phead->next != phead);LTNode* find = phead->next;while (find!=phead){if (find->data == x){return find;}find = find->next;}return NULL;
}
//在pos之后插入数据
void LTInsert(LTNode* pos, LTDataType x)
{assert(pos && pos->next != pos);LTNode* newnode = LTBuyNode(x);
//	pos   newnode  pos->nextnewnode->next = pos->next;newnode->prev = pos;pos->next->prev = newnode;pos->next = newnode;
}//删除指定位置
void LTErase(LTNode* pos)
{assert(pos);LTNode* del = pos;// pos->prev  pos  pos->nextpos->prev->next = pos->next;pos->next->prev->prev;free(del);del = NULL;}
//销毁链表
void LTDesTroy(LTNode* phead)
{assert(phead);LTNode* del = phead->next;LTNode* next = phead->next;while (next!=phead){free(del);del = next = next->next;}free(phead);phead = NULL;}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com