数据源结构之双链表的增删查改

1.双向链表

1.1概念与结构

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

1.2 实现双向链表

在这里,由于双链表和单链表的基本逻辑是一样的,我将只保留重要部分的注释,详情逻辑请参考单链表!

和之前一样,我们还是创建三个文件。

这是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;
//初始化
ltnode* ltinit();
//尾插
void ltpushback(ltnode* phead, ltdatatype x);
//头插
void ltpushfront(ltnode* phead, ltdatatype);
//尾删
void ltpopback(ltnode* phead);
//头删
void ltpopfront(ltnode* pead);
//查找
ltnode* ltfind(ltnode* phead, ltdatatype x);
//在pos位置之后插入数据
void ltinsert(ltnode* pos, ltdatatype);
//在pos位置之前插入数据
void ltinsertbefore(ltnode* pos, ltdatatype x);
//删除pos结点
void lterase(ltnode* pos);
//打印
void ltprint(ltnode* phead);
//销毁
void ltdestroy(ltnode* phead);

这是list.c文件

#include"list.h"
//申请结点
ltnode* ltbuynode(ltdatatype x)
{
	ltnode* node = (ltnode*)malloc(sizeof(ltnode));
	assert(node);
	node->data = x;
	node->next = node->prev = node;  
	
	return node;//由于我们创建的是双向循环链表,故不可置为NULL,要让结点自己转起来。
}
//初始化
ltnode* ltinit()
{
	ltnode* phead = ltbuynode(-1);
	return phead;
}
//打印
void ltprint(ltnode* phead)
{
	//由于链表是循环的,而恰好Head里面没有有效数据,故让pcur从head->next开始遍历,直到head为止
	ltnode* pcur = phead->next;
	while (pcur != phead)
	{
		printf("%d->", pcur->data);
		pcur = pcur->next;
	}
	printf("\n");
}
//尾插  (插入小技巧:先对要插入的结点进行操作,要尽可能减小对原链表的影响)
void ltpushback(ltnode* phead, ltdatatype x)
{
	assert(phead);
	ltnode* newnode = ltbuynode(x);
	newnode->next = phead;
	newnode->prev = phead->prev;   //由于链表是循环的,尾结点就是Phead的前一个结点,可以看一下例图
	phead->prev->next = newnode;
	phead->prev = newnode;
}
//头插(插在哨兵位结点之后,插在哨兵位结点之前叫尾插)
void ltpushfront(ltnode* phead, ltdatatype x)
{
	assert(phead);
	ltnode* newnode = ltbuynode(x);
	newnode->next = phead->next;
	newnode->prev = phead;
	phead->next->prev = newnode;
	phead->next = newnode;
}
//尾删              (删除小技巧:把所有指向删除节点的箭头干掉,然后frree))
void ltpopback(ltnode* phead)
{
	assert(phead && phead->next != phead);
	ltnode* del = phead->prev;
	del->prev->next = phead;
	phead->prev = del->prev;
	free(del);
	del = NULL;
}
//头删
void ltpopfront(ltnode* phead)
{
	assert(phead && phead->next != phead);
	ltnode* del = phead->next;
	phead->next = del->next;
	phead->prev->prev = phead;
	free(del);
	del = NULL;
}

//查找
ltnode* ltfind(ltnode* phead, ltdatatype x)
{
	ltnode* pcur = phead->next;
	while (pcur != phead)
	{
		if (pcur->data == x)
		{
			return pcur;
		}
		pcur = pcur->next;
	}
	return NULL;
}
//在pos位置之后插入数据
void ltinsert(ltnode* pos, ltdatatype x)
{
	assert(pos);
	ltnode* newnode = ltbuynode(x);
	newnode->next = pos->next;
	newnode->prev = pos;
	pos->next->prev = newnode;
	pos->next = newnode;
}
//删除Pos结点
void lterase(ltnode* pos)
{
	assert(pos);
	pos->prev->next = pos->next;
	pos->next->prev = pos->prev;
	free(pos);
	pos = NULL;
}
//在pos位置之前插入数据
void ltinsertbefore(ltnode* pos, ltdatatype x)
{
	assert(pos);
	ltnode* newnode = ltbuynode(x);
	newnode->next = pos;
	newnode->prev = pos->prev;
	pos->prev->next = newnode;
	pos->prev = newnode;
}
//销毁
void ltdestroy(ltnode* phead)
{
	assert(phead);
	ltnode* pcur = phead->next;
	while (pcur != phead)
	{
		ltnode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	//此时pcur指向phead,而phead还没有被销毁
	free(phead);
	phead = NULL;
}

这是Test.c文件

#include"list.h"
void listtest()
{
	ltnode* plist = ltinit();

	//尾插
	ltpushback(plist, 1);
	ltprint(plist);
	ltpushback(plist, 2);
	ltprint(plist);
	ltpushback(plist, 3);
	ltprint(plist);
	ltpushback(plist, 4);
	ltprint(plist);

	//头插
	ltpushfront(plist, 4);
	ltprint(plist);
	ltpushfront(plist, 3);
	ltprint(plist);
	ltpushfront(plist, 2);
	ltprint(plist);
	ltpushfront(plist, 1);
	ltprint(plist);

	//尾删
	ltpopback(plist);
	ltprint(plist);
	ltpopback(plist);
	ltprint(plist);

	//头删
	ltpopfront(plist);
	ltprint(plist);
	ltpopfront(plist);
	ltprint(plist);

	//查找
	ltnode* find = ltfind(plist, 4);
	if (find == NULL)
	{
		printf("没找到!\n");
	}
	else
	{
		printf("找到了\n");
	}

	//在pos位置之后插入数据
	ltinsert(find, 5);
	ltprint(plist);


	//删除Pos结点
	lterase(find);                            //函数执行后,find会被释放掉
	ltprint(plist);

	//在pos位置之前插入数据
	ltnode* find1 = ltfind(plist, 5);      //由于此处的find已经被释放掉了,故需要重新定义一下
	ltinsertbefore(find1, 6);       
	ltprint(plist);
	//销毁
	ltdestroy(plist);
}
int main()
{
	listtest();
	return 0;
}

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值