双向循环链表(哨兵头节点)

        为了解决单链表的缺点,我们可以改进一下单链表,使其变的可以随机访问,并且使增删查改更加简单逻辑清晰。

        为了使代码逻辑更加清晰,我使用了哨兵位头节点:意思就是当链表为空的时候,也有一个节点存在,它不存储有效数据,这样做的好处是:只需要传一级指针就可以直接改变头节点(哨兵位节点)的 next 和 pre 的值进而改变链表。

        根据图片,可以知道,双向循环链表的一大特点就是链表既可以向前找也可以向后找,循环意味着没有结束,这意味着如果遍历链表的指针与phead(哨兵位头节点)相等时链表结束(遍历指针为phead->next)。

看着比较复杂,其实代码逻辑比较简单。

先拿尾插函数和打印函数示范:

struct Seqlist
{
	struct Seqlist* next;
	struct Seqlist* pre;
	int val;
};
void Seqlist_init(struct Seqlist** plist) {
	*plist = malloc(sizeof(struct Seqlist));
	(*plist)->next = *plist;
	(*plist)->pre = *plist;
}
void SeqlistPushback(struct Seqlist* plist,int num) {
	struct Seqlist* new_node = malloc(sizeof(struct Seqlist));
	struct Seqlist* tail = plist->pre;
	new_node->val = num;
	plist->pre = new_node;
	tail->next = new_node;
	new_node->next = plist;
	new_node->pre = tail;
}

Seqlist是创建的结构体,其中有指向前后的指针和存储的整数。
Seqlist_init是为了创建哨兵位头节点,因为是双向循环,所以前后指针都指向自己。

        SeqlistPushback是尾插函数,首先创建一个新节点,然后找到尾(即头的前一个plist->pre),给新节点的 val 赋值,最后四行代码,前两行先让 tail 和 phead 都指向 new_node,然后再让new_node 都指向 tail 和 phead 。
        如果链表为空,同样适用,这时 phead 同时也是 tail ,前两行让 phead 的 next 和 pre 都指向 new_node ,然后让 new_node 的 next 和 pre 都指向 phead 。

 

void SeqlistPrint(struct Seqlist* plist) {
	struct Seqlist* cur = plist->next;
	while (cur != plist) {
		printf("%d ", cur->val);
		cur = cur->next;
	}
}

        打印函数也比较简单,让cur指针指向哨兵位头节点的下一个节点,cur=cur->next,并打印链表。如果cur等于phead,就说明已经遍历了一遍链表,退出函数。

        那如果我们想随意位置的增加或删除节点呢,逻辑同样比较简单,首先我们要写一个查找链表节点返回地址的查找函数:

struct Seqlist* FindPositon(struct Seqlist* phead,int num) {
	struct Seqlist* cur = phead->next;
	while (cur!=phead)
	{
		if (cur->val == num) {
			return cur;
	}
		cur = cur->next;
	}
	return -1;
}

在这个函数中,当要找的 num 等于 cur->val 时返回 cur 的地址,然后我们需要一个删除函数:

void SeqlistCancel(struct Seqlist* pos) {
	struct Seqlist* pos_pre = pos->pre;
	struct Seqlist* pos_next = pos->next;
	pos_pre->next = pos_next;
	pos_next->pre = pos_pre;
	free(pos);
}

逻辑非常简单,就是把这个位置的前后链接起来最后 free 释放掉 pos。 

还有内存销毁函数:

void SeqlistFree(struct Seqlist* plist) {
	struct Seqlist* cur = plist->next;
	while (cur != plist) {
		cur = cur->next;
		free(cur->pre);
	}
	free(plist);
}

最后展示一下结果:

这就是文章的全部内容了,希望对你有所帮助,如有错误欢迎评论。 

  • 8
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值