♥注:未经博主同意,不得转载。
链表是另一种形式的链式存储结构,它是线性链表的一种变形。在线性链表中,每个结点的指针都指向它的下一个结点,最后一个结点的指针域为空,表示链表的结束。若使最后一个结点的指针指向头结点,则链表呈环状,这样的链表称为循环链表。
循环链表当然也分为单链表和双向列表。
通常情况下,在循环链表中设立尾指针而不设头指针,可使某些操作简化。
循环链表的定义和操作与单链表类似,只是循环结束条件有所不同,下面只给出单循环链表的定义和部分操作,至于双向循环链表可能会在以后的项目中出现,到时再进一步探讨。
单循环链表定义如下:
1 typedef int Data;
2
3 struct Node
4 {
5 Data data; //数据
6 Node* next; //指向后继的指针
7 };
8
9 class CList
10 {
11 Node* head; //创建头结点
12 public:
13 CList() //构造函数
14 {
15 head = new Node;
16 head->next = head; //头尾相接
17 }
18 ~CList(); //析构函数
19
20 Data GetElem(int i); //取第i个元素的值
21 bool IsEmpty(); //判断是否为空链表
22 void Create(Data* a , int n); //创建长度为n的循环单链表(头插法)
23 void Create1(Data* a , int n); //创建长度为n的循环单链表(尾插法)
24 Node* Locate(Data e,int* i); //查找值为e的结点,返回指向e的指针
25 void Insert(Data x,int i); //将数据元素x插入到第i个位置
26 Data Delete(int i); //删除第i个元素
27 //int _Delete(Data e); //删除值为e的第一个元素
28 int Size(); //返回链表的长度
29 void Clear(); //清空
30 void Print(); //显示元素
31 };
函数功能实现如下:
1 //计算链表长度
2 int CList::Size()
3 {
4 Node* p; //创建指针p
5 int k;
6 p=head->next; //p指向第一个元素结点
7 k=0;
8 while(p!=head)
9 {
10 p=p->next;
11 ++k;
12 }
13 return k;
14 }
15
16 //显示所有元素
17 void CList::Print()
18 {
19 Node* p; //创建指针p
20 p=head->next; //p指向第一个元素结点
21 while(p!=head)
22 {
23 cout<<p->data<<" ";
24 p=p->next;
25 }
26 cout<<endl;
27 }
28
29 //取元素
30 Data CList::GetElem(int i)
31 {
32 if(head->next == NULL) //为空链表
33 {
34 cout<<"此链表为空"<<endl;
35 exit(0);
36 }
37 else
38 {
39 Node* p; //创建指针p
40 int k;
41 p=head; //p指向头结点
42 k=0;
43 while(p&&k<i) //p移到i的位置
44 {
45 p=p->next;
46 k++;
47 }
48 return (p->data);
49 }
50 } //此算法的时间复杂度为O(n)
51
52 //插入操作
53 void CList::Insert(Data x,int i)
54 {
55 Node* p=head;
56 int k=0;
57 while(p&&k<i-1) // 将p指到第i个位置
58 {
59 p=p->next;
60 ++k;
61
62 if(p==head)
63 p=p->next;
64 }
65 Node* s = new Node; //创建此结点
66 if(!s)
67 {
68 cout<<"空间分配失败"<<endl;
69 exit(0);
70 }
71
72 s->data=x; //将元素存入创建的结点
73 s->next=p->next;
74 p->next=s;
75 }
76
77 //删除操作
78 Data CList::Delete(int i)
79 {
80 Node* p = head;
81 int k=0;
82 while(p&&k<i-1) //将p指到要删除的位置
83 {
84 p=p->next;
85 ++k;
86
87 if(p==head)
88 p=p->next;
89 }
90 Node* q = p->next; //暂存删除结点
91
92 p->next = q->next; //将结点隔离出来
93 Data e=q->data; //将删除的元素储存起来
94 delete q; //释放将要删除的结点
95 return e;
96 }
97
98 //判断链表是否为空
99 bool CList::IsEmpty()
100 {
101 if(head->next==NULL)
102 {
103 cout<<"此链表为空"<<endl;
104 return true;
105 }
106 else
107 {
108 cout<<"此链表非空"<<endl;
109 return false;
110 }
111 }
112
113 //建立单循环链表
114 //第一种是头插法
115 void CList::Create(Data* a,int n)
116 {
117 Node* p=NULL;
118 Node* q=NULL;
119 for(int i=n-1;i>=0;--i)
120 {
121 p=new Node; //创建新结点
122 p->data=a[i]; //将元素存入结点
123
124 p->next=head->next; //将新加入结点指向头结点后面
125 head->next=p; //将头结点指向新加入的结点
126 }
127 }
128
129 //第二种是尾插法
130 void CList::Create1(Data* a,int n)
131 {
132 Node* p=NULL;
133 Node* q=head; //创建中间结点指针
134 for(int i=0;i<n;++i)
135 {
136 p=new Node; //创建储存元素的新结点
137 p->data=a[i]; //将元素存入创建的结点
138 p->next=q->next; //插入到终端结点之后
139 q->next=p; //终端结点指向新建结点
140 q=p; //q指向新建结点
141 }
142 p->next=NULL;
143 }
144
145 //查找给定值的结点
146 Node* CList::Locate(Data e,int *i)
147 {
148 *i=1;
149 Node* p=head->next;
150
151 while(p!=head) //p不为空
152 {
153 if(p->data==e) //找到元素
154 return p;
155 else
156 {
157 p=p->next;
158 ++(*i);
159 }
160 }
161 cout<<"当前链表中无此元素"<<endl;
162 exit(0);
163 return NULL;
164 }
165
166 //清空单循环链表
167 //保留表头结点,把链表中的
168 //其余所有结点全部释放。
169 void CList::Clear()
170 {
171 Node* p=NULL;
172 Node* q=NULL;
173 p=head->next;
174 while(p!=head)
175 {
176 q=p;
177 p=p->next;
178 delete q;
179 }
180 head->next = NULL;
181 }
182
183 //析构函数
184 //释放链表中的所有元素。
185 CList::~CList()
186 {
187 Node* p;
188 p=head;
189 while(p!=head)
190 {
191 p=p->next;
192 delete head;
193 head=p;
194 }
195 }
测试程序则放在main函数里:
1 int main()
2 {
3 int i=0;
4 Data e;
5 int a[8]={2,4,6,8,5,1,7,9};
6
7 CList list; //创建链表类
8 list.IsEmpty(); //判断链表是否为空
9 list.Create(a,8); //将数据插入
10 list.Print(); //显示
11 cout<<"链表长度:"<<list.Size()<<endl;
12
13 cout<<"输入要插入的元素和位置:";
14 cin>>e>>i;
15 list.Insert(e,i); //插入数据
16 list.Print();
17 cout<<"当前链表长度为"<<list.Size()<<endl<<endl;
18
19 cout<<"输入要查找的元素值:";
20 cin>>e;
21 list.Locate(e,&i); //查找某元素
22 cout<<"这是第"<<i<<"个元素"<<endl<<endl;
23
24 list.IsEmpty(); //判断链表是否为空
25
26 cout<<"输入要查找的元素位置:";
27 cin>>i;
28 e=list.GetElem(i); //查找第i个位置的元素
29 cout<<"这个元素值为:"<<e<<endl<<endl;
30
31 list.IsEmpty(); //判断链表是否为空
32
33 cout<<"输入要删除的元素位置:";
34 cin>>i;
35 e=list.Delete(i); //删除第i个位置的元素
36 cout<<"这个元素值为:"<<e<<endl;
37 list.Print();
38 cout<<"当前链表长度为"<<list.Size()<<endl<<endl;
39
40 cout<<"输入要删除的元素位置:";
41 cin>>i;
42 e=list.Delete(i); //删除第i个位置的元素
43 cout<<"这个元素值为:"<<e<<endl;
44 list.Print();
45 cout<<"当前链表长度为"<<list.Size()<<endl<<endl;
46
47 list.Clear();
48 list.IsEmpty(); //判断链表是否为空
49
50 return 0;
51 }
测试情况如下:

到此,线性表的几种基本实现已经结束了,下方可查看几种线性表的具体实现:
1.顺序存储:http://www.cnblogs.com/tenjl-exv/p/7469316.html
2.单链表:http://www.cnblogs.com/tenjl-exv/p/7470075.html
3.双向链表:http://www.cnblogs.com/tenjl-exv/p/7475518.html
这里说一下循环链表的优点:
① 从表中任意结点出发均可访问到表中其他结点,这使得某些操作在循环链表上容易实现。
② 插入删除操作中不需区分尾节点还是中间结点,以使操作简化
来源:https://www.cnblogs.com/tenjl-exv/p/7476246.html