链表以及简单的接口实现

目录

1.链表的概念

2.链表的分类

3.链表的实现(不带头单向非循环链表)

3.1打印链表

3.2创建链表

3.3尾插数据

3.4头插

3.5尾删

3.6头删

3.7查找

3.8在指定位置之前插入

3.9删除指定位置之后

3.10销毁链表

4.顺序表与链表的比较


1.链表的概念

链表不同于顺序表,顺序表在物理存储结构上连续,而链表是非连续非顺序的,其中间的元素是通过一个个指针所连接起来的。

由此可看出,链表的特点就是在物理上不连续,在逻辑上连续。

2.链表的分类

链表可分为:单向与双向链表,带头与不带头链表。循环与不循环链表。我们最常用的还是两种结构:不带头单向非循环链表,带头双向循环链表。

其中各有各的特点:

不带头单向非循环链表结构简单,多数情况下是以其他数据结构的子结构出现。

带头双向循环链表结构复杂,但是逻辑简单,一般用于单独存放数据。

3.链表的实现(不带头单向非循环链表)

typedef int SLTDataType;
typedef struct SListNode
{
	SLTDataType data;
	struct SListNode* next;
}SLTNode;


void SLTPrint(SLTNode* phead);                                      //打印链表
SLTNode* BuyListNode(SLTDataType x);                                //创建链表
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 SLTInsertAfter( SLTNode* pos, SLTDataType x);                  //在pos之后插入
void SLTEraseAfter(SLTNode* pos);                                   //删除pos之后
void SLTDestory(SLTNode** pphead);                                  //销毁链表

3.1打印链表

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

3.2创建链表

SLTNode* BuyListNode(SLTDataType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	newnode->data = x;
	newnode->next = NULL;
	return newnode;
}

3.3尾插数据

void SLTPushBack(SLTNode** pphead, SLTDataType x)     //尾插
{
	SLTNode* newnode = BuyListNode(x);
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		SLTNode* cur = *pphead;
		while (cur->next != NULL)
		{
			cur = cur->next;
		}
		cur->next = newnode;
	}

}

Tips:传参时不能直接传递插入的链表地址,因为形参为临时变量,如果头指针为空,第一个链表直接拷贝进形参并不能改变实参中的链表,因此需要传二级指针。 

3.4头插

void SLTPushFront(SLTNode** pphead, SLTDataType x) //头插
{
	SLTNode* newnode = BuyListNode(x);//链表的地址
	newnode->next = *pphead;
	*pphead = newnode;
}

3.5尾删

void SLTPopBack(SLTNode** pphead)      //尾删
{
	//1.空
	assert(*pphead);
	//2.一个节点
	//3.多个节点
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
	}
	else
	{
		SLTNode* tail = *pphead;
		while (tail->next->next)
		{
			tail = tail->next;
		}
		free(tail->next);
		tail->next = NULL;
	}

}

3.6头删

void SLTPopFront(SLTNode** pphead) //头删
{
	//空
	assert(*pphead);
	//有链表
	SLTNode* cur = *pphead; //指向第一个,也就是将删除的
	*pphead = (*pphead)->next;
	free(cur);
	cur = NULL;
}

3.7查找

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

3.8在指定位置之前插入

void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)      //在pos之前插入
{
	assert(pos);
	//pos为第一个链表
	//pos不为第一个链表
	if (*pphead == pos)
	{
		SLTPushFront(pphead, x);
	}
	else
	{
		SLTNode* cur = *pphead;
		SLTNode* newnode = BuyListNode(x);
		while (cur->next)                   //遍历找到pos的前一个链表
		{
			if (cur->next == pos)           //把前一个链表的next改为新链表
			{
				cur->next = newnode;
				break;
			}
			cur = cur->next;
		}
		newnode->next = pos;                //把新链表与后面的连接起来
	}
}

3.9删除指定位置之后

void SLTEraseAfter(SLTNode* pos)                        //删除pos之后
{
	assert(pos);
	assert(pos->next);
	SLTNode* cur = pos->next;
	pos->next = cur->next;
	free(cur);
	cur = NULL;
}

3.10销毁链表

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

4.顺序表与链表的比较

顺序表优点:

1.可以通过下标来随机访问

2.CPU缓存利用率高

缺点:

1.内存不够需要扩展内存,容易造成内存浪费

2.插入删除数据可能需要挪动其他数据

链表优点:

1.不需要扩展内存,不存在浪费问题

2.任意位置插入删除简单

缺点:

1.CPU缓存利用率低

2.随机访问麻烦

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值