数据结构——双向循环链表(声明、初始化、增加、删除、搜索修改、顺序逆序遍历)

以下是数据结构中双向循环链表的声明、初始化、增加节点、删除节点、插入节点、搜索节点的基本操作:

声明链表

typedef struct LNode{
	int data;
	LNode *next;
	LNode *pre;
}Lnode,*LinkList; 

每一个节点有三个属性分别是
data:数据;
*next:下一个节点的地址;
*pre:上一个节点的地址。

初始化链表

void initial(LinkList &List){//指针的指针
	List = new Lnode;
	List->next = List;
	List->pre = List;
	List->data = 0;
	cout<<"循环链表创建完毕(首结点data:0)"<<endl; 
}

因为是双向链表,首节点的后继节点和前驱节点都是自己本身。

增加节点

void addNode(Lnode *&List,int data){
	LNode *p = List;
	LNode *start = List;//标记起点 
	while(p->next!=start){
		p = p->next;
	}
	LNode *newnode = new LNode;//尾插新节点 
	newnode->next = start;//尾节点 后继为 首节点 
	start->pre = newnode;//首节点的 前驱为 尾节点 (此处容易遗漏,要注意) 
	newnode->data = data; 
	p->next = newnode;//将尾节点接到链表末尾 
	newnode->pre = p;// 双向连接 
	
}

void add(Lnode *&List){
	int c;
	while(1){
		cout<<"请输入新增节点的data(输入0停止新增):"; 
		cin>>c;
		if(c==0){
			break;
		}
		addNode(List,c);
	}
	cout<<"节点新增完成!";
	showList(List); 
}

步骤如下:
1、声明新节点
2、将链表尾节点的后继由首节点更换为新节点;
3、新节点的后继设为尾节点;
4、将首节点的前驱设为新节点;
5、将新节点的前驱设为之前的尾节点(此时新节点成为新的尾节点)。

删除节点

void delNode(Lnode *&List,int index){
	LNode *p = List;
	LNode *s = List;
	int i = 0;
	while(i+1<index && p->next->next!=s->next){
		i++;
		p = p->next;
	}
	if(i+1<index){
		cout<<"超出循环链表长度"<<endl; 
	}else{
		Lnode *t = new Lnode;
		t = p->next;
		p->next = t->next;
		t->next->pre = p;
		delete t;
	}
}
void del(Lnode *&List){
	int index;
	cout<<"请输入要删除的元素下标(从1开始):";
	cin>>index;
	delNode(List,index);
	showList(List);
}

步骤:
1、根据下标开始遍历;
2、p->next->next!=s->next目的有两个:
2.1:是让p可以顺利遍历到最后一个元素(如果只写p->next!=s会导致当p遍历到最后一个节点时就跳出循环,删除不了最后一个节点);
2.2:在到达被删除的节点前一个节点就要开始准备删除工作,否则p到达被删除的节点时会导致删除该节点后后段链表接不上前段链表(即导致链表断裂)
3、声明中间变量节点(被删除的节点);
4、被删节点的前一个节点的后继节点变为被删节点的后继节点;
5、被删节点的后继的前驱节点设为被删节点的前驱节点;

插入节点

void insertNode(Lnode *&List,int index){
	int i = 1; 
	LNode *p = List;
	Lnode *start = List;
	while(p->next != start && i < index){ 
		i++;
		p = p->next;
	}
	if(i<index || p->next == start){
		cout<<i<<endl;
		cout<<"插入位置超出链表长度!";
	}else{
		LNode *newnode = new LNode;
		newnode->next = p->next;
		newnode->pre = p;
		p->next->pre = newnode;
		int data;
		cout<<"请输入新节点的data:";
		cin>>data;
		newnode->data = data;
		p->next = newnode;
	}
} 

void insert(Lnode *&List){
	cout<<"请输入插入数据的位置(从1开始算):";
	int index;
	cin>>index;
	insertNode(List,index);
	cout<<"节点插入完成!";
	showList(List);
}

步骤:
1、到达插入位置前一个位置指针p停止移动;
2、设置新节点;
3、将新节点的前驱设为p,
4、将新节点的后继设为p的后继,
5、将p的后继设为新节点;
注意:3、4、5的顺序不能随意改变,如果先执行5,会导致新节点的后继是新节点本身。

搜索(修改)节点

void searchNode(LinkList &List, int data){
	LinkList p = List->next;//从头结点的下一个节点开始搜索 
	LinkList start = List;//首地址 
	int index = 1;
	int flat = 1;
	while(p!=start){
		if(p->data == data){
			cout<<"查找成功!第"<<index<<"个节点data为"<<data<<endl;
			flat = 0;
			//此处不设置跳出是为了查询相同元素的全部下标位置
			//如果只需要查询第一次出现的位置,在此处设置跳出循环即可 
		}
		p = p->next;
		index++;
	}
	if(flat){
		cout<<"No data '"<<data<<"' in this list!"<<endl; 
	}
}

void search(LinkList &List){
	int data;
	cout<<"请输入要查找的data:";
	cin>>data;
	searchNode(List,data);
}

特别说明:此处的指针从首节点的下一个地址开始搜索。

顺序与逆序遍历双向循环链表

void showList(LinkList &List){//等价于LNode *&List
	LNode *p = List;
	LNode *start = List;
	int index = 0;
	cout<<"当前链表信息:"<<endl;
	cout<<"顺序:"<<endl;
	cout<<"(首节点)"<<p->data<<"<-->";
	p = p->next; 
	while(p!=start){
		cout<<p->data<<"<-->";
		p = p->next;
	}
	cout<<p->data<<"(首节点)"<<endl;
//	**************************************//
	p = List;//重置p指针的位置 
	cout<<"逆序:"<<endl;
	cout<<"(首节点)"<<p->data<<"<-->";
	p = p->pre; 
	while(p!=start){
		cout<<p->data<<"<-->";
		p = p->pre;
	}
	cout<<start->data<<"(首节点)"<<endl;
}

注意:逆序的时候记得将p指针的地址重新设置回链表头部。

完整源代码

/*
		广西师范大学 计算机科学与工程学院 
		GuangXi Normal University College of Computer Science and Engineering  
		Student STZ 
*/ 
#include<iostream>
#include<stdio.h>
using namespace std;

typedef struct LNode{
	int data;
	LNode *next;
	LNode *pre;
}Lnode,*LinkList; 

void initial(LinkList &List){//指针的指针
	List = new Lnode;
	List->next = List;
	List->pre = List;
	List->data = 0;
	cout<<"循环链表创建完毕(首结点data:0)"<<endl; 
}

void showList(LinkList &List){//等价于LNode *&List
	LNode *p = List;
	LNode *start = List;
	int index = 0;
	cout<<"当前链表信息:"<<endl;
	cout<<"顺序:"<<endl;
	cout<<"(首节点)"<<p->data<<"<-->";
	p = p->next; 
	while(p!=start){
		cout<<p->data<<"<-->";
		p = p->next;
	}
	cout<<p->data<<"(首节点)"<<endl;
//	**************************************//
	p = List;//重置p指针的位置 
	cout<<"逆序:"<<endl;
	cout<<"(首节点)"<<p->data<<"<-->";
	p = p->pre; 
	while(p!=start){
		cout<<p->data<<"<-->";
		p = p->pre;
	}
	cout<<start->data<<"(首节点)"<<endl;
}

void addNode(Lnode *&List,int data){
	LNode *p = List;
	LNode *start = List;//标记起点 
	while(p->next!=start){
		p = p->next;
	}
	LNode *newnode = new LNode;//尾插新节点 
	newnode->next = start;//尾节点 后继为 首节点 
	start->pre = newnode;//首节点的 前驱为 尾节点 (此处容易遗漏,要注意) 
	newnode->data = data; 
	p->next = newnode;//将尾节点接到链表末尾 
	newnode->pre = p;// 双向连接 
	
}

void add(Lnode *&List){
	int c;
	while(1){
		cout<<"请输入新增节点的data(输入0停止新增):"; 
		cin>>c;
		if(c==0){
			break;
		}
		addNode(List,c);
	}
	cout<<"节点新增完成!";
	showList(List); 
}
void delNode(Lnode *&List,int index){
	LNode *p = List;
	LNode *s = List;
	int i = 0;
	while(i+1<index && p->next->next!=s->next){
		i++;
		p = p->next;
	}
	if(i+1<index){
		cout<<"超出循环链表长度"<<endl; 
	}else{
		Lnode *t = new Lnode;
		t = p->next;
		p->next = t->next;
		t->next->pre = p;
		delete t;
	}
}
void del(Lnode *&List){
	int index;
	cout<<"请输入要删除的元素下标(从1开始):";
	cin>>index;
	delNode(List,index);
	showList(List);
}

void insertNode(Lnode *&List,int index){
	int i = 1; 
	LNode *p = List;
	Lnode *start = List;
	while(p->next != start && i < index){ 
		i++;
		p = p->next;
	}
	if(i<index || p->next == start){
		cout<<i<<endl;
		cout<<"插入位置超出链表长度!";
	}else{
		LNode *newnode = new LNode;
		newnode->next = p->next;
		newnode->pre = p;
		p->next->pre = newnode;
		int data;
		cout<<"请输入新节点的data:";
		cin>>data;
		newnode->data = data;
		p->next = newnode;
	}
} 

void insert(Lnode *&List){
	cout<<"请输入插入数据的位置(从1开始算):";
	int index;
	cin>>index;
	insertNode(List,index);
	cout<<"节点插入完成!";
	showList(List);
}

void searchNode(LinkList &List, int data){
	LinkList p = List->next;//从头结点的下一个节点开始搜索 
	LinkList start = List;//首地址 
	int index = 1;
	int flat = 1;
	while(p!=start){
		if(p->data == data){
			cout<<"查找成功!第"<<index<<"个节点data为"<<data<<endl;
			flat = 0;
			//此处不设置跳出是为了查询相同元素的全部下标位置
			//如果只需要查询第一次出现的位置,在此处设置跳出循环即可 
		}
		p = p->next;
		index++;
	}
	if(flat){
		cout<<"No data '"<<data<<"' in this list!"<<endl; 
	}
}

void search(LinkList &List){
	int data;
	cout<<"请输入要查找的data:";
	cin>>data;
	searchNode(List,data);
}


void menu(LinkList &List){
	int c = 0;
	while(1){
		cout<<"请选择操作:"<<endl;
		cout<<"1:新增节点"<<endl;
		cout<<"2:插入节点"<<endl;
		cout<<"3:删除节点"<<endl;
		cout<<"4:展示节点"<<endl;
		cout<<"5:搜索节点"<<endl;
		cout<<"6:退出系统"<<endl;
		cin>>c;
		switch(c){
			case 1:add(List);break;
			case 2:insert(List);break;
			case 3:del(List);break;
			case 4:showList(List);break;
			case 5:search(List);break; 
			case 6:return;
			default:;
		} 
	}
}

int main(){
	Lnode *List;
	initial(List);
	menu(List);
	return 0;
}

效果图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

特别说明:本程序仅挑取关于链表的关键操作进行介绍,对于边界问题(如删除头结点)等特殊情况并没有做出处理。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

芣苢的成长之路

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

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

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

打赏作者

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

抵扣说明:

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

余额充值