数据结构-链式表之带头双向循环链表

目录

一、定义;

二、程序实现

三、释放内存问题

四、双向循环链表与单链表之间的差异


一、定义;

带头双向循环列表,结构较复杂,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向循环列表。虽然结构复杂,但是该结构会使程序实现简单方便。

  • 下图可以看到,它有一个不存储数据的头节点,每个节点中有三个值,一个是prev指针,一个是数据域data,和一个next指针改变。
  • 其中头结点的prev指向尾节点,尾结点的next指向头节点,形成了循环
  • 其余节点的prev指向上一个节点,next指向下一个节点,构成了双向
  • 当链表只有头结点时,头结点的prev指针与next指针都指向head本身。这一特点使得在插入与删除结点时,不会出现对空指针取值问题,且头结点始终存在,因此指向头结点的指针始终不变。不需再像单链表操作时需要改变头指针的值(传递头指针地址进入函数内)。

二、程序实现

1、结构体代码

SeqList* SeqListCreatNode(int data)//创建结点
{
	SeqList* newone=(SeqList*)malloc(sizeof(SeqList));
	newone->data=data;
	newone->prev=NULL;//新创建结点指针设为NULL;
	newone->next=NULL;
	return newone;
}

2、初始化头结点

定义一个指向头结点的指针phead。

SeqList* SeqListNodeInit(int data)//头结点初始化
{
	SeqList* phead=SeqListCreatNode(data);//创建一个指向头结点的指针phead
	phead->next=phead;                    //头结点内指针指向自身
	phead->prev=phead;
	return phead;
}
int main()
{
	//初始化头结点。先创建再初始化
	SeqList* phead=SeqListNodeInit(0);
	SeqListPushBack(phead,1);
	SeqListPushBack(phead,2);
	SeqListPushBack(phead,3);
	SeqListPushFront(phead,4);
	SeqListPopBack(phead);
	SeqListPopFront(phead);
	SeqListShow(phead);
}

3、函数定义

typedef struct SeqList SeqList;
SeqList* SeqListCreatNode(int data);//创建结点
SeqList* SeqListNodeInit(int data);//头结点初始化
void SeqListPushBack(SeqList* phead,int data);//尾插函数
void SeqListPushFront(SeqList* phead,int data);//头插函数
void SeqListPopBack(SeqList* phead);//尾删函数
void SeqListPopFront(SeqList* phead);//头删函数
void SeqListShow(SeqList* phead);//显示函数

4、尾插函数

void SeqListPushBack(SeqList* phead,int data)//尾插函数
{
	SeqList* newone=SeqListCreatNode(data);
	SeqList* temp=phead->prev;
	temp->next=newone;
	newone->prev=temp;
	phead->prev=newone;
	newone->next=phead;	
}

5、头插函数

void SeqListPushFront(SeqList* phead,int data)//头插函数
{
	SeqList* newone=SeqListCreatNode(data);
	SeqList* temp=phead->next;
	phead->next=newone;
	newone->prev=phead;
	temp->prev=newone;
	newone->next=temp;
}

6、尾删函数

void SeqListPopBack(SeqList* phead)//尾删函数
{
	
	if(phead->prev==phead){
		printf("无数据可删除");
		return;
	}
	else{
		SeqList* temp=phead->prev;
		phead->prev=temp->prev;
		temp->prev->next=phead;
		free(temp);
		temp=NULL;
		
	}
}

7、头删函数

void SeqListPopFront(SeqList* phead)//头删函数
{
	if(phead->next==phead){
			printf("无数据可删除");
			return;
		}
		else{
			SeqList* temp=phead->next;
			phead->next=temp->next;
			temp->next->prev=phead;
			free(temp);
			temp=NULL;
			
		}
}

三、释放内存问题

销毁链表时,需要遍历所有要释放的结点,依次free,最后再释放头结点
最后将phead置为空指针代表链表为空,即销毁完成。

四、双向循环链表与单链表之间的差异

1、单链表

(1)单链表不能从后面往前。

(2)找不到它的前驱(上一个地址)(尾插,尾删,中插,中删)都要找到它的前一个节点。

(3)没有带头的节点:要用二级指针进行传参,不用改变传过来指针。

2、双向循环链表

(1)带头节点的好处:不存储有效数据,带哨兵位的头节点不存入链表的长度,使得尾插更加方便,每次都在头后进行连接。不需要传递头指针的地址(二级指针)。

(2)双向的好处:方便找到他的前一个节点。

(3)循环的好处:头指向尾,尾指向头,头的前一个节点就是尾,方便找尾节点。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值