栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

数据结构--双向循环链表的实现

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

数据结构--双向循环链表的实现

前言

之前学习了单链表的实现,单链表在实现的过程中,尾删,尾插是比较麻烦的,时间复杂度为O(N),而双向循环链表就不会有这样的顾虑,双向循环链表的结构是很有优势的。具体优势在实现的时候会显现出来。

双向循环链表的实现

 

在实现双向循环链表时,我们选择了插入头指针。

//头文件包
#include
#include
#include

typedef int Data;


typedef struct List
{
	Data val;
	struct List* next;
	struct List* prev;
}List,list;

//初始化
List* InitList(List** phead);

List* DestoryList(List* phead);
//尾插
void PushBack(List* phead, Data x);
void PopBack(List* phead);

void PushFront(List* phead, Data x);
void PopFront(List* phead);

void EraseList(List* phead, List** ppos);
void InsertList(List* phead, List* pos, Data x);
void InsertList2(List* phead, List* pos, Data x);

void PrintList(List* phead);

List* FindList(List* phead, Data x);
 初始化函数
List* Buynewnode(Data x)
{
	List* newnode = (List*)malloc(sizeof(list));
	if (newnode == NULL)
	{
		printf("malloc failed");
		exit(-1);
	}
	newnode->val = x;
	newnode->next = NULL;
	newnode->prev = NULL;

	return newnode;
}

List* InitList(List** pphead)
{
	(*pphead) = Buynewnode(0);
	(*pphead)->next = *pphead;
	(*pphead)->prev = *pphead;
	return *pphead;
}

//初始化链表也就是为了插入一个哨兵结点,Buynewnode函数在后面还会用到
//在这里初始化链表参数用了二级指针,这是因为要改变结点指针的值,所以传二级指针
插入类函数
//尾插
void PushBack(List* phead, Data x)
{
	assert(phead);
	
	List* newnode = Buynewnode(x);
	List* tail = phead->prev;//找尾

	tail->next = newnode;
	newnode->next = phead;
	newnode->prev = tail;
	phead->prev = newnode;

}
//尾插的时候,结构优势就来了,就是在找尾时不用再从头遍历找尾,

//头插
void PushFront(List* phead, Data x)
{
	assert(phead);

	List* next = phead->next;
	List* newnode = Buynewnode(x);

	phead->next = newnode;
	newnode->prev = phead;
	newnode->next = next;
	next->prev = newnode;
}

//任意位置插入函数
void InsertList(List* phead, List* pos, Data x)//插到pos前面
{
	assert(pos);

	List* newnode = Buynewnode(x);
	List* prevtail = pos->prev;

	prevtail->next = newnode;
	newnode->next = pos;
	newnode->prev = prevtail;
}

void InsertList2(List* phead, List* pos, Data x)//插到pos后面
{
	assert(pos);

	List* newnode = Buynewnode(x);
	List* next = pos->next;

	pos->next = newnode;
	newnode->prev = pos;
	newnode->next = next;
	next->prev = newnode;

}
//在插入进任意位置的时候,无论是插在pos前面还是后面时间复杂度都很低
//这就是结构优势,不用找尾。
删除类函数
//尾删
void PopBack(List* phead)
{
	assert(phead);
	assert(phead->next != NULL);//保证链表中不只有哨兵结点

	List* tail = phead->prev;
	List* prevtail = tail->prev;

	prevtail->next = phead;
	phead->prev = prevtail;

	free(tail);
}
//在删除的过程中,要注意的一点就是不要将哨兵结点删除,可以用
//assert断言一下,头删的时候也是。

//头删
void PopFront(List* phead)
{
	assert(phead);
	assert(phead->next != phead);

	List* cur = phead->next;
	List* next = cur->next;
    free(cur);
	phead->next = next;
	next->prev = phead;
}

//任意位置删除
void EraseList(List* phead, List** ppos)
{
	assert(phead && *ppos);

	List* prevtail = (*ppos)->prev;
	List* next = (*ppos)->next;

	prevtail->next = next;
	next->prev = prevtail;
	free(*ppos);
	*ppos = NULL;
}
//在这里pos可以传一级指针,也可以传二级指针,如果最后给pos赋NULL,就要用二级指针;
//如果不修改pos的值,就用一级指针。修不修改pos的值都可以。
打印函数
void PrintList(List* phead)
{
	assert(phead);

	List* cur = phead->next;
	while (cur != phead)
	{
		printf("%d ", cur->val);
		cur = cur->next;
	}
	printf("n");
}
找结点函数
List* FindList(List* phead, Data x)
{
	assert(phead);

	List* cur = phead->next;
	while (cur != phead)
	{
		if (cur->val == x)
			return cur;
		cur = cur->next;
	}
	return NULL;
}

销毁链表

List* DestoryList(List* phead)
{
	assert(phead);
	List* cur = phead->next;
	while (cur != phead)
	{
		List* next = cur->next;
		free(cur);
		cur = next;
	}
	free(phead);
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/778973.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号