【数据结构】链表

9 篇文章 2 订阅
7 篇文章 1 订阅

目录

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后面插入11
	 SLTNode* 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->next
	pos->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->next
	pos->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             newnode
	newnode->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->next
	newnode->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->prev
	del->prev->next = phead;
	phead->prev = del->prev;

	//删除del
	free(del);
	del = NULL;
}

5.7  LTPopFront () 头删

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

	//phead  del del->next
	LTNode* del = phead->next;

	//删除del
	phead->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->next

	newnode->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->next
	pos->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             newnode
	newnode->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->next
	newnode->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->prev
	del->prev->next = phead;
	phead->prev = del->prev;

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

	//phead  del del->next
	LTNode* del = phead->next;

	//删除del
	phead->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->next

	newnode->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->next
	pos->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;
	
}

评论 52
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

熬夜苦读学习

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值