带头 双向 循环 链表——C语言实现

        既然有带头 那么就有不带头 为什么我要将带头 而不讲不带头?

        在之前我讲单链表时就说过 如果不带头会出现讨论的情况 为什么会出现讨论的情况

        假设链表有一个节点 进行尾插 就只是将新的节点连接到链表的尾节点之后 

        那么如果链表没有节点 就没有尾节点 自然也就不能尾插 也就是说这个新节点要作为链表的头节点 这个操作自然就和上面的尾插不同了 所以要进行讨论

那么接下来就开始 带头双向循环链表的讲解

既然是链表就离不开结构体 就先定义一个结构体出来 

这是双向循环链表的图形

 如上图所示 该结构体中有两个指针 一个指向下一个节点 另一个指向前一个节点 循环也就是尾节点的next 指向头节点 将prior改为prev 头结点的prev指向尾节点

如此就形成了一个环形结构 

typedef struct ListNode
{
	int val;
	struct ListNode* next;
	struct ListNode* prev;
}ListNode;

接下来就对节点进行初始化

void ListInti(ListNode* frist)
{
	frist->val = 0;
	frist->next = frist;
	frist->prev = frist;
}

 写一个开辟节点的函数

ListNode* BuyNode(int x)
{
	ListNode* tmp = (ListNode*)malloc(sizeof(ListNode));
	if (tmp == NULL)
	{
		printf("节点开辟失败.");
		return;
	}
	tmp->val = x;
	return tmp;
}

因为下面尾插和头插 都要用到开辟节点 所以都要用 那不如写一个函数进行赋用

void ListPushBack(ListNode* frist, int x)
{
	ListNode* node = BuyNode(x);
	ListNode* tmp = frist->prev;

	tmp->next = node;
	node->prev = tmp;

	node->next = frist;
	frist->prev = node;
}

void ListPushFront(ListNode* frist, int x)
{
	ListNode* node = BuyNode(x);
	ListNode* tmp = frist->next;

	node->prev = frist;
	tmp->prev = node;
	frist->next = node;
	node->next = tmp;
}

计算链表的大小

static int ListSize(ListNode* frist)
{
	ListNode* cur = frist->next;
	int sz = 1;
	while (frist != cur)
	{
		sz++;
		cur = cur->next;
	}
	return sz;
}

下面就是任意位置插入的函数

void ListNodeInsert(ListNode* frist, int pos, int x)
{
	assert(frist);

	if (pos > ListSize(frist))
	{
		printf("插入位置,超过链表长度.\n");
		return;
	}

	ListNode* node = BuyNode(x);
	ListNode* cur = frist, * str = cur->next;
	while (pos > 1)
	{
		pos--;
		cur = cur->next;
		str = str->next;
	}
	node->next = str;
	node->prev = cur;
	cur->next = node;
	str->prev = node;
}

既然可以任意位置插入 那么头插和尾插 都可以赋用这个函数

void ListPushBack(ListNode* frist, int x)
{
	//ListNode* node = BuyNode(x);
	//ListNode* tmp = frist->prev;

	//tmp->next = node;
	//node->prev = tmp;

	//node->next = frist;
	//frist->prev = node;
	ListNodeInsert(frist, ListSize(frist), x);
}

void ListPushFront(ListNode* frist, int x)
{
	//ListNode* node = BuyNode(x);
	//ListNode* tmp = frist->next;

	//node->prev = frist;
	//tmp->prev = node;
	//frist->next = node;
	//node->next = tmp;
	ListNodeInsert(frist, 1, x);
}

节点的增添已经写完了 接下来就是删除的操作

因为节点在堆上开辟  所以要写一个释放节点的函数

void ListNodeDestroy(ListNode* tmp)
{
	free(tmp);
	tmp->next = NULL;
	tmp->prev = NULL;
}

如果链表是空的 那么就没有必要删除

static bool Empty(ListNode* frist)
{
	return frist->next == frist;
}

那么开始就写删除节点的函数 尾删和头删

void ListPopBack(ListNode* frist)
{
	assert(frist);
	assert(!Empty(frist));

	ListNode* tmp = frist->prev, * tail = tmp->prev;
	tail->next = frist;
	frist->prev = tail;

	ListNodeDestroy(tmp);
}

void ListPopFront(ListNode* frist)
{
	assert(frist);
	assert(!Empty(frist));

	ListNode* tmp = frist->next, * tail = tmp->next;
	frist->next = tail;
	tail->prev = frist;

	ListNodeDestroy(tmp);
}

既然上面插入有任意位置 那么就有任意位置的删除操作

void ListNodeErase(ListNode* frist,int pos)
{
	assert(frist);

	ListNode* cur = frist->next, * str = cur->next;
	while (pos > 1)
	{
		pos--;
		cur = cur->next;
		str = str->next;
	}
	str->prev = cur->prev;
	cur->prev->next = str;

	ListNodeDestroy(cur);
}

双向链表的增添 删除 已经完成

链表的打印

static void Print(ListNode* frist)
{
	assert(frist);
	ListNode* cur = frist->next;
	while (frist != cur)
	{
		printf("%d->", cur->val);
		cur = cur->next;
	}
	printf("NULL\n");
}

上面就是双向带头循环链表

ListNode* ListFind(ListNode* frist,int x)
{
	assert(frist);
	assert(!Empty(frist));

	ListNode* cur = frist->next;
	int pos = 0;
	while (frist != cur)
	{
		pos++;
		if (cur->val == x)
		{
			printf("存在该数据 在第%d个位置\n",pos);
		}
		cur = cur->next;
	}
}

完整的双向循环链表链表结构

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>


typedef struct ListNode
{
	int val;
	struct ListNode* next;
	struct ListNode* prev;
}ListNode;


void ListInti(ListNode* frist)
{
	frist->val = 0;
	frist->next = frist;
	frist->prev = frist;
}

ListNode* BuyNode(int x)
{
	ListNode* tmp = (ListNode*)malloc(sizeof(ListNode));
	if (tmp == NULL)
	{
		printf("节点开辟失败.");
		return;
	}
	tmp->val = x;
	return tmp;
}

static void Print(ListNode* frist)
{
	assert(frist);
	ListNode* cur = frist->next;
	while (frist != cur)
	{
		printf("%d->", cur->val);
		cur = cur->next;
	}
	printf("NULL\n");
}

static bool Empty(ListNode* frist)
{
	return frist->next == frist;
}

void ListNodeDestroy(ListNode* tmp)
{
	free(tmp);
	tmp->next = NULL;
	tmp->prev = NULL;
}

void ListPopBack(ListNode* frist)
{
	assert(frist);
	assert(!Empty(frist));

	ListNode* tmp = frist->prev, * tail = tmp->prev;
	tail->next = frist;
	frist->prev = tail;

	ListNodeDestroy(tmp);
}

void ListPopFront(ListNode* frist)
{
	assert(frist);
	assert(!Empty(frist));

	ListNode* tmp = frist->next, * tail = tmp->next;
	frist->next = tail;
	tail->prev = frist;

	ListNodeDestroy(tmp);
}

void ListDestroy(ListNode* frist)
{
	assert(frist);
	assert(!Empty(frist));

	ListNode* tmp = frist->next, * cur = tmp->next;
	while (frist != tmp)
	{
		ListNodeDestroy(tmp);
		tmp = cur;
		cur = cur->next;
	}
}

static int ListSize(ListNode* frist)
{
	ListNode* cur = frist->next;
	int sz = 1;
	while (frist != cur)
	{
		sz++;
		cur = cur->next;
	}
	return sz;
}

void ListNodeInsert(ListNode* frist, int pos, int x)
{
	assert(frist);

	if (pos > ListSize(frist))
	{
		printf("插入位置,超过链表长度.\n");
		return;
	}

	ListNode* node = BuyNode(x);
	ListNode* cur = frist, * str = cur->next;
	while (pos > 1)
	{
		pos--;
		cur = cur->next;
		str = str->next;
	}
	node->next = str;
	node->prev = cur;
	cur->next = node;
	str->prev = node;
}

void ListNodeErase(ListNode* frist,int pos)
{
	assert(frist);

	ListNode* cur = frist->next, * str = cur->next;
	while (pos > 1)
	{
		pos--;
		cur = cur->next;
		str = str->next;
	}
	str->prev = cur->prev;
	cur->prev->next = str;

	ListNodeDestroy(cur);
}

//void ListPushBack(ListNode* frist, int x)
//{
//	ListNode* node = BuyNode(x);
//	ListNode* tmp = frist->prev;
//
//	tmp->next = node;
//	node->prev = tmp;
//
//	node->next = frist;
//	frist->prev = node;
//}
//
//void ListPushFront(ListNode* frist, int x)
//{
//	ListNode* node = BuyNode(x);
//	ListNode* tmp = frist->next;
//
//	node->prev = frist;
//	tmp->prev = node;
//	frist->next = node;
//	node->next = tmp;
//}

void ListPushBack(ListNode* frist, int x)
{
	//ListNode* node = BuyNode(x);
	//ListNode* tmp = frist->prev;

	//tmp->next = node;
	//node->prev = tmp;

	//node->next = frist;
	//frist->prev = node;
	ListNodeInsert(frist, ListSize(frist), x);
}

void ListPushFront(ListNode* frist, int x)
{
	//ListNode* node = BuyNode(x);
	//ListNode* tmp = frist->next;

	//node->prev = frist;
	//tmp->prev = node;
	//frist->next = node;
	//node->next = tmp;
	ListNodeInsert(frist, 1, x);
}

ListNode* ListFind(ListNode* frist,int x)
{
	assert(frist);
	assert(!Empty(frist));

	ListNode* cur = frist->next;
	int pos = 0;
	while (frist != cur)
	{
		pos++;
		if (cur->val == x)
		{
			printf("存在该数据 在第%d个位置\n",pos);
		}
		cur = cur->next;
	}
}

void test()
{
	ListNode frist;
	ListInti(&frist);

	ListPushBack(&frist, 1);
	ListPushBack(&frist, 2);
	ListPushBack(&frist, 3);
	ListPushBack(&frist, 4);

	ListPushFront(&frist, 9);
	ListPushFront(&frist, 8);
	ListPushFront(&frist, 7);
	ListPushFront(&frist, 6);

	ListPopBack(&frist);
	ListPopBack(&frist);

	ListPopFront(&frist);
	ListPopFront(&frist);

	ListNodeInsert(&frist, 1, 10);
	ListNodeInsert(&frist, 4, 11);
	ListNodeInsert(&frist, 5, 12);
	ListNodeInsert(&frist, 8, 13);

	ListNodeErase(&frist, 2);
	ListNodeErase(&frist, 7);

	ListFind(&frist, 0);
	ListFind(&frist, 2);

	Print(&frist);

	ListDestroy(&frist);

}

int main()
{

	test();

	return 0;
}

上续双向循环链表已完成链表~

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

菜鸡爱玩

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

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

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

打赏作者

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

抵扣说明:

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

余额充值