双向链表(循环)的基础操作(C++)

引言

对于释放空间和删除元素,都还有些问题,希望能够得到评论提示。

链表元素(结构体)

想保存的值和前元素、后元素指针

struct Node
{
	int val;
	Node * next;
	Node * prev;
};

链表的创建

先创建一个头结点指针,然后构建创建函数,以头结点指针为参数并返回指针对象

int main()
{
	Node * head = (Node *)malloc(sizeof(Node));
	head->next = NULL;
	head->prev = NULL;
	head->val = 10;
	head = Create(head);

由于我是在C++在线编译器上做的操作,输入不便,因此选择用循环直接输入是个9个数来完成创建。
在这里,我把q始终作为尾结点看待,为当前节点元素申请空间,并赋值,使其的后对象指针始终指向头结点head,前对象指针指向前对象p。
把p作为倒数第二个节点看待,p的后对象指针始终指向当前对象q,头结点的前对象指针也始终指向当前对象q。

Node * Create(Node * head)
{
	int i = 9;
	Node * p,* q;
	p = head;
	for(;i > 0;i--)
	{
		q = (Node *)malloc(sizeof(Node));
		q->val = i;
		q->next = head;
		q->prev = p;
		p->next = q;
		head->prev = q;	
		p = q;
	}
	return head;
}

双向链表的最初两个元素的关系就像下图所示在这里插入图片描述
接下来就是插入后续元素,选用的是后插法,原理同上
在这里插入图片描述

链表的显示(遍历)

循环遍历输出了所有元素对象,函数和结果如下图

void Show(Node * head)
{
	Node * c = head;
	cout << "当前数:" << c->val << endl;
	cout << "上一个数:" << c->prev->val << endl;
	cout << "下一个数:" << c->next->val << endl;
	c = c->next;
	do
	{
		cout << "当前数:" << c->val << endl;
		cout << "上一个数:" << c->prev->val << endl;
		cout << "下一个数:" << c->next->val << endl;
		c = c->next;
	}
	while(c != head);
	
	return;
}

在这里插入图片描述

链表的排序

使用的是冒泡排序,其中有个理解小错误,写的过程中发现了,也展示出来大家看看。

//冒泡排序
Node * Sort(Node * head)
{
	bool changeflg = true;
	while(changeflg)
	{
		changeflg = false;
		Node * p = head;
		for(;p->next != head;p = p->next)
		//只能走到倒数第二个元素,尾节点并不在循环中
		{
			if(p->val > p->next->val)
			{
				//交换其中的值
				int temp;
				temp = p->val;
				p->val = p->next->val;
				p->next->val = temp;
				changeflg = true;
			}
		}
		/*
		//当前p处于尾节点,再进行比较
		if(p->val > p->next->val)
		{
			//交换其中的值
			int temp;
			temp = p->val;
			p->val = p->next->val;
			p->next->val = temp;
			changeflg = true;
		}
		*/
		//这里刚开始有错误的理解,以为没有进行比较
		//其实已经作为p->next进行过比较了
	}
	return head;
}

在这里插入图片描述

链表的插入(头插)

使用的是头插,由于是双向链表,很快就可以找到尾节点,其实也可以快速实现尾插;但如果是单向链表,需要先通过遍历找到尾节点,所以建议使用头插。

Node * Add(Node * head)
{
	Node * q = (Node *)malloc(sizeof(Node));
	q->val = 11;
	//这里的顺序很重要,不然会丢失节点
	q->next = head->next;
	q->prev = head;
	head->next->prev = q;
	head->next = q;
	return head;
}

按照1,2,3,4四个步骤建立链

链表的删除(按值删除)

遍历查找是否值相等,只适用于唯一值情况。如若删除所有重复值,需另写

void Delete(Node * head,int val)
{
	Node * p = head;
	Node * n = NULL;
	for(;p->next != head;p = p->next)
	{
		if(p->val == val)
		{
			p->prev->next = p->next;
			p->next->prev = p->prev;
			free(p);
			return;
		}	
	}
	//尾节点也得判断
	if(p->val == val)
	{
		p->prev->next = p->next;
		p->next->prev = p->prev;
		free(p);
	}
	return;
}

链表的清除

注意需要释放掉曾经申请的内存

Node * Clear(Node * head)
{
	Node * p = head;
	Node * n = head->prev;
	while(p->next != head)
	{
		Node * q = p->next;
		free(p);
		p = q;
	}
	free(n);
	head = NULL;
	return head;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值