以下是数据结构中双向循环链表的声明、初始化、增加节点、删除节点、插入节点、搜索节点的基本操作:
声明链表
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;
}
效果图
特别说明:本程序仅挑取关于链表的关键操作进行介绍,对于边界问题(如删除头结点)等特殊情况并没有做出处理。