C语言_双向循环链表的基本操作

目录:
1、初始化
2、头部插入
3、头部删除
4、尾部插入
5、尾部删除
6、打印链表
7、任意位置插入
8、查找值为data的节点
9、指定位置删除
10、销毁链表

###1、初始化:

创建一个节点,给节点赋值为0;因为是循环链表,所以让它的_pNext指针域和_pPre 指针域都指向自己

void DCListInit (DCList** p)//初始化
{
	DCList *cur = NULL;
	assert (p != NULL);
	cur = (DCList*)malloc (sizeof (DCList));
	if (NULL == cur)
	{
		printf ("初始化操作失败\n");
		exit (EXIT_FAILURE);
	}
	*p = cur;
	(*p)->data = 0;
	(*p)->_pNext = *p;
	(*p)->_pPre = *p;
}

运行结果如图:
这里写图片描述

###创建一个新节点
在操作过程中,像插入等操作,还需要创建新节点,将其写成一个函数,代码如下:

DCList* DCBuyNode(DCDataType data)
{
	DCList* cur = (DCList*)malloc(sizeof (DCList));
	if (cur == NULL)
	{
		perror ("DCBuyNode::malloc >>");
		return  NULL;
	}
	cur->data = data;
	cur->_pNext = NULL;
	cur->_pPre = NULL;
	return cur;
}

###2、头部插入
先找到最后一个节点,用tail标记,在让新节点接在链表第一个节点的前面,然后再将新节点和头结点相连,最后让新节点作为链表的头,如下图:

这里写图片描述

void PushFrontDCList (DCList** p, DCDataType data)//头插
{
	DCList* NewNode = NULL;
	DCList* tail = NULL;	//标记最后一个节点
	assert (p != NULL);

	NewNode = DCBuyNode (data);

	tail = (*p);
	while (tail->_pNext != *p)
	{
		tail = tail->_pNext;
	}

	NewNode->_pNext = (*p);
	(*p) ->_pPre = NewNode;
	tail ->_pNext = NewNode;
	NewNode->_pPre = tail;
	*p = NewNode;
}

通过调用打印链表的函数,执行结果如下:
这里写图片描述

###3、头部删除
头部删除时删除的是第一个节点,要分情况讨论,当链表只有一个节点时:只需要删除这一个节点;当有多个节点时,分两步,先把第一个节点从链表上拆下来,在删除第一个节点,让现在链表中的第一个节点作为新链表的第一个节点;

这里写图片描述

void PopFrontDCList (DCList**p)//头删
{
	DCList *del = NULL;
	DCList *tail = NULL;
	DCList *cur = NULL;

	assert (p != NULL);

	del = *p;

	//当链表只有一个节点时
	if ((*p)->_pNext == *p)
	{
		free (del);
		del = NULL;
		*p = NULL;
		printf ("链表为空!!!\n");
		return ;
	}
	//链表有两个及以上的节点时
	tail = (*p)->_pNext;
	cur = (*p)->_pNext;

	while (tail->_pNext != *p)	//找最后一个节点
	{
		tail = tail->_pNext;
	}

	tail ->_pNext = cur;
	cur->_pPre = tail;	//把第一个节点从链表上拆下来

	free (*p);	//删除第一个节点
	(*p) = NULL;

	(*p) = cur;
	
}

通过调用打印函数,执行结果如下:
这里写图片描述
###4、链表的打印
这里的链表打印有两种,主要是因为在初始化时让第一个节点的值为零,所以实际上链表中的值还多出来一个0,当使用头插时,0在链表中最后一个节点,当使用尾插时,0在链表中最前面的节点,具体代码如下:

void PrintDCList_F (DCList* p)	//打印链表(头插的打印方式)
{
	DCList* cur = p;
	assert (p != NULL);
	if (p->_pNext == p)
	{
		printf ("链表为空!!!\n");
		return;
	}
	while (cur->_pNext != p)
	{
		printf ("%d ", cur->data);
		cur = cur->_pNext;
	}
	printf ("\n");
}

void PrintDCList_B (DCList* p)	//打印链表(尾插的打印方式)
{
	DCList* cur = p->_pNext;
	assert (p != NULL);
	if (p->_pNext == p)
	{
		printf ("链表为空!!!\n");
		return;
	}
	while (cur != p)
	{
		printf ("%d ", cur->data);
		cur = cur->_pNext;
	}
	printf ("\n");
}

5、尾部插入
尾部插入也分为两步:先找最后的一个节点,在将新节点和最后一个节点和第一个节点连起来,这里找最后一个节点也可以通过第一个节点的前驱节点来找。

这里写图片描述



void PushBackDCList (DCList** p, DCDataType data)	//尾部插入
{
	DCList* cur = NULL;
	DCList* tail = NULL;
	assert (p != NULL);
	
	cur = DCBuyNode(data);	//新节点
	tail = *p;

	while (tail->_pNext != *p)	//找最后一个节点
	{
		tail = tail->_pNext;
	}

	tail->_pNext = cur;
	cur->_pPre = tail;
	cur->_pNext = (*p);
	(*p)->_pPre = cur;
}

运行结果:
这里写图片描述

6、尾部删除
这里的删除方法也与之前的类似,就是找到要删除的点,将它从链表上拆下来并把它删除,所以后面的就不再细说了;
这里写图片描述

void PopBackDCList (DCList** p)	//尾删
{
	DCList* del = NULL;
	DCList* pre = NULL;
	assert(p != NULL);

	del = *p;

	if ((*p)->_pNext == (*p))	//如果只有一个节点
	{
		free (del);
		del = NULL;
		*p = NULL;
		printf ("链表为空!!\n");
		return ;
	}

	//如果有多个节点
	del = *p;

	while (del->_pNext != *p)
	{
		pre = del;
		del = del->_pNext;
	}

	pre->_pNext = *p;
	(*p)->_pPre = pre;
	free (del);
	del = NULL;
}

这里写图片描述

###7、查找节点

查找节点就是简单的遍历链表,一次比较是否是要查找的节点

DCList* FindDCNode (DCList* p, DCDataType data)	//查找值为data的节点
{
	DCList* cur = p->_pNext;
	while (p != cur)
	{
		if (cur->data == data)
		{
			return cur;
		}
		cur = cur->_pNext;
	}
	return NULL;
}

这里写图片描述

###8、任意位置插入

void InsertDCList (DCList** p, DCList* pos, DCDataType  data)	//任意位置插入
{
	DCList* new_node = NULL;
	assert (p != NULL && pos != NULL);

	new_node = DCBuyNode(data);
	pos->_pPre->_pNext = new_node;
	new_node->_pPre = pos->_pPre;
	new_node->_pNext = pos;
	pos->_pPre = new_node;

}

这里写图片描述

###9、任意位置删除

void DeleteDCNode (DCList** p, DCList* pos)	//任意位置删除元素
{
	DCList* del = NULL;
	assert (p != NULL);
	pos->_pNext->_pPre = pos->_pPre;
	pos->_pPre->_pNext = pos->_pNext;
	free (pos);
	pos = NULL;
}

这里写图片描述

10、销毁链表
遍历链表,一次销毁所有节点

void DestroyDCList (DCList** p)	//销毁链表
{
	DCList* pre = NULL;
	DCList* tail = NULL;	//用来标记最后一个节点
	assert (p != NULL);
	tail = (*p)->_pPre;
	while (*p != tail)
	{
		pre = (*p);
		(*p) = (*p)->_pNext;
		free (pre);
		pre = NULL;
	}
	free (*p);
	(*p) = NULL;
}

猜你喜欢

转载自blog.csdn.net/A__B__C__/article/details/82633089