关于双向带头链表

一、双向带头链表的概念

双向带头链表是链表的一种,一个结点由数据部分、指向前一个结点的指针和指向后一个结点的指针三部分组成。

typedef struct ListNode{           //定义双链表结点类型
    LTDataType data;                 //数据域
    struct ListNode *prev,*next;   //前驱和后继指针
}ListNode;

尽管看起来双向链表的结构较单向链表更为复杂,但是操作更为简便。双向链表相比单向链表在尾插、某个结点之前加入新结点、删除某结点等操作上,更加方便。

而头结点的存在,能减少对输入结点为空情况的检查,使操作更方便。

二、双向带头链表的基本操作

1.创建头结点

头结点创建以后数据域为空,其前驱指针和后继指针都指向自己,也是判断链表是否为空的依据。

ListNode* ListCreate()
{
	ListNode* head = (ListNode*)malloc(sizeof(ListNode));
	if (head == NULL)
	{
		perror("malloc fail!");
		exit(1);
	}
	head->next = head;
	head->prev = head;
	return head;
}

2.在pos之前插入结点

首先,需要申请一个新结点,考虑写成一个函数,后续直接调用

ListNode* BuyNewNode(LTDataType x)
{
	ListNode* NewNode = (ListNode*)malloc(sizeof(ListNode));
	if (NewNode == NULL)
	{
		perror("malloc fail!");
		exit(1);
	}
	NewNode->data = x;
	NewNode->next = NewNode->prev = NULL;
	return NewNode;
}

然后,调整前后结点的指针指向,建议先完成新结点的前驱后驱指针指向,再修改前驱结点的后继指针和后继结点的前驱指针

void ListInsert(ListNode* pos, LTDataType x)
{
	ListNode* cur = BuyNewNode(x);
	cur->next = pos;
	cur->prev = pos->prev;
	pos->prev->next = cur;
	pos->prev = cur;
}

3.删除pos结点

删除结点则只需修改其前驱后继结点的相关指针,然后free掉pos结点

void ListErase(ListNode* pos)
{
	pos->prev->next = pos->next;
	pos->next->prev = pos->prev;
	free(pos);
}

4.头插头删,尾插尾删以及链表摧毁

有了Insert和Erase函数以后,以上操作均可通过套用函数来完成,而链表的摧毁则仅需要一个循环,以链表是否为空为条件,不断删除头结点后的第一个结点,最后单独删除头结点即可。

5.打印链表

以链表是否为空为条件,对链表进行遍历,需要注意的是,头结点为空

void ListPrint(ListNode* pHead)
{
	ListNode* head = pHead->next;
	while (head != pHead)
	{
		printf("%d->", head->data);
		head = head->next;
	}
	printf("\n");
}

6.找特定结点

同样使用链表是否为空为条件,对链表进行遍历,寻找符合条件的结点。

以上为带头双向链表的相关操作。作为数据结构经常会使用到的链表,相关操作一定要熟练,套用函数增加效率可行,但是背后的基本逻辑需掌握。

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值