数据结构-线性表-单循环链表(使用尾指针)(c++)
目录
单循环链表
说明
单循环链表和单链表(参考单链表)大致一样,只是尾结点要指向头结点,本文是使用尾结点rear来表示,之所以使用尾指针,是因为如果使用头结点来寻找列表最后一个元素时间复杂度为O(n),如果使用尾结点来寻找列表最后一个元素时间复杂度为O(1)
注意
- 第一个元素地址表示:rear->next->next;最后一个元素地址:rear
- 头指针的表示,单链表使用front来标识头指针,单循环链表使用rear->next来表示
- 单链表使用p->next=NULL判断是否为尾结点,单循环链表使用p==rear判断是否为尾结点
(一)无参构造函数
建立尾结点,使尾结点指针域指向自己,说明链表为空
template<class T>
CircleList<T>::CircleList()
{
rear=new Node<T>;
rear->next=rear;
}
(二)有参构造函数
这里的方法相当于单链表中使用的尾插法,
- 为rear开辟空间
- 创建头指针Headr,并把rear的地址赋给Headr
- 使用for循环将数组依次加入到列表中
- 创建一个临时结点temp
- 为temp值域赋值,并把其地址赋给rear->next
- 修改rear地址
- 最后将rear指回头结点
template<class T>
CircleList<T>::CircleList(T a[],int len)
{
rear = new Node<T>;
Node<T>* Headr;
Headr = rear;
for (int i=0;i<len;i++)
{
Node<T>* temp = new Node<T>;
temp->data = a[i];
rear->next = temp;
rear = temp;
}
rear->next = Headr;
}
(三)析构函数
与单链表相似,只是最后rear要单独释放
template<class T>
CircleList<T>::~CircleList()
{
Node<T>* p=rear->next;
while(p!=rear)
{
rear->next=p;
p=p->next;
delete rear->next;
}
delete rear;
}
(四)获取长度
与单链表相似,只是j的初始值要为1,因为while循环的终止条件为p!=rear,但是rear为最后一个元素,需要算上,所以j的初始值为1
template<class T>
int CircleList<T>::GetLength()const
{
int j=1;
Node<T>* p=rear->next->next;
while(p!=rear)
{
j++;
p=p->next;
}
return j;
}
(五)打印数组
因为while循环的终止条件为p!=rear,但是rear为最后一个元素,所以需要单独打印rear;其中if(i%5==4)是控制5个元素为一行
template<class T>
void CircleList<T>::Print()const
{
Node<T>* p=rear->next->next;
int i=0;
while(p!=rear)
{
std::cout<<p->data<<" ";
if(i%5==4)
std::cout<<std::endl;
p=p->next;
i++;
}
std::cout<<rear->data<<std::endl;
}
(六)获取第i个元素的地址
与单链表相似,需要注意的是,如果取最后一个元素,需要使用if(GetLength()==i)return rear;单独判断
template<class T>
Node<T>* CircleList<T>::Get(int i)const
{
int j=0;
Node<T>* p=rear->next;
if(GetLength()==i)return rear;
while(p!=rear&&j!=i)
{
p=p->next;
j++;
}
return p;
}
(七)插入
和单链表略有不同
- 先判断插入位置是否正确
- 然后在插入
template<class T>
void CircleList<T>::Insert(int i,T x)
{
Node<T>* p=rear->next;
if(i<0||i>GetLength())throw"位置异常";
if(i!=1)
p=Get(i-1);
Node<T>* s=new Node<T>;
s->data=x;
s->next=p->next;
p->next=s;
}
(八)删除
- 获取第i-1位置的地址
- q表示第i个元素
- 摘链
- 释放
如果删除最后一个元素需要单独释放:
- 用temp存储最后元素的地址
- 让rear指向倒数第二个元素
- 摘链,让倒数第二个元素指向头结点
- 释放
template<class T>
void CircleList<T>::Delete(int i)
{
Node<T>* p=rear->next;
if(i!=1)
p=Get(i-1);
if(i==GetLength())
{
Node<T>* temp=rear;
rear=p;
rear->next=temp->next;
delete temp;
}
else
{
Node<T>* q=p->next;
p->next=q->next;
delete q;
}
}
(九)获取值为x的元素的位置
template<class T>
int CircleList<T>::Location(T x)const
{
int j=0;
Node<T>* p=rear->next->next;
if(x==rear->data)return GetLength();
while(p!=rear)
{
j++;
if(p->data==x)
return j;
p=p->next;
}
}
(十)排序
使用的是冒泡排序,循环的终止条件与单链表不同
template<class T>
void CircleList<T>::sort()
{
for(int i=1;i<=CircleList<T>::GetLength();i++)
{
Node<T>* p=rear->next->next;
while(p!=rear)
{
if(p->data>p->next->data)
{
T t;
t=p->next->data;
p->next->data=p->data;
p->data=t;
}
p=p->next;
}
}
}
(十一)连接
- 保存b链的头结点
- b链的尾指向当前链表的头
- 当前链表的尾,指向b链的第一个元素
- 修改尾指针
- 将b链置空,并且把b.rear指向这个节点
template<class T>
void CircleList<T>::Connect(CircleList<T> &b)
{
if(b.rear==b.rear->next)return;
Node<T>* p=b.rear->next;//保存b链的头结点
b.rear->next=rear->next;//b链的尾指向当前链表的头
rear->next=p->next;//当前链表的尾,指向b链的第一个元素
rear=b.rear;//修改尾指针
b.rear=p->next=p;//将b链置空,并且把b.rear指向这个节点
}
(十二)整个文件
CircleList.h
#ifndef CIRCLELIST_H_
#define CIRCLELIST_H_
#include<iostream>
template<class T>
struct Node
{
T data;
struct Node<T>* next;
};
template<class T>
class CircleList
{
private:
Node<T>* rear;
public:
CircleList();
CircleList(T a[],int len);
~CircleList();
int GetLength()const;
void Print()const;
void Insert(int i,T x);
void Delete(int i);
Node<T>* Get(int i)const;
int Location(T x)const;
void sort();
void Connect(CircleList<T> &b);
};
template<class T>
CircleList<T>::CircleList()
{
rear=new Node<T>;
rear->next=rear;
}
template<class T>
CircleList<T>::CircleList(T a[],int len)
{
rear = new Node<T>;
Node<T>* Headr;
Headr = rear;
for (int i=0;i<len;i++)
{
Node<T>* temp = new Node<T>;
temp->data = a[i];
rear->next = temp;
rear = temp;
}
rear->next = Headr;
}
template<class T>
CircleList<T>::~CircleList()
{
Node<T>* p=rear->next;
while(p!=rear)
{
rear->next=p;
p=p->next;
delete rear->next;
}
delete rear;
}
template<class T>
int CircleList<T>::GetLength()const
{
int j=1;
Node<T>* p=rear->next->next;
while(p!=rear)
{
j++;
p=p->next;
}
return j;
}
template<class T>
void CircleList<T>::Print()const
{
Node<T>* p=rear->next->next;
int i=0;
while(p!=rear)
{
std::cout<<p->data<<" ";
if(i%5==4)
std::cout<<std::endl;
p=p->next;
i++;
}
std::cout<<rear->data<<std::endl;
}
template<class T>
void CircleList<T>::Insert(int i,T x)
{
Node<T>* p=rear->next;
if(i<0||i>GetLength())throw"位置异常";
if(i!=1)
p=Get(i-1);
Node<T>* s=new Node<T>;
s->data=x;
s->next=p->next;
p->next=s;
}
template<class T>
void CircleList<T>::Delete(int i)
{
Node<T>* p=rear->next;
if(i!=1)
p=Get(i-1);
if(i==GetLength())
{
Node<T>* temp=rear;
rear=p;
rear->next=temp->next;
delete temp;
}
else
{
Node<T>* q=p->next;
p->next=q->next;
delete q;
}
}
template<class T>
Node<T>* CircleList<T>::Get(int i)const
{
int j=0;
Node<T>* p=rear->next;
if(GetLength()==i)return rear;
while(p!=rear&&j!=i)
{
p=p->next;
j++;
}
return p;
}
template<class T>
int CircleList<T>::Location(T x)const
{
int j=0;
Node<T>* p=rear->next->next;
if(x==rear->data)return GetLength();
while(p!=rear)
{
j++;
if(p->data==x)
return j;
p=p->next;
}
}
template<class T>
void CircleList<T>::sort()
{
for(int i=1;i<=CircleList<T>::GetLength();i++)
{
Node<T>* p=rear->next->next;
while(p!=rear)
{
if(p->data>p->next->data)
{
T t;
t=p->next->data;
p->next->data=p->data;
p->data=t;
}
p=p->next;
}
}
}
template<class T>
void CircleList<T>::Connect(CircleList<T> &b)
{
if(b.rear==b.rear->next)return;
Node<T>* p=b.rear->next;//保存b链的头结点
b.rear->next=rear->next;//b链的尾指向当前链表的头
rear->next=p->next;//当前链表的尾,指向b链的第一个元素
rear=b.rear;//修改尾指针
b.rear=p->next=p;//将b链置空,并且把b.rear指向这个节点
}
#endif // CIRCLELIST_H_
UseCircleList.cpp
#include<iostream>
#include"CircleList.h"
const int SIZE=10;
int main()
{
using std::cout;
using std::endl;
int ss[SIZE]={9,3,4,1,5,0,8,6,2,7};
int qq[5]={0,1,2,3,4};
CircleList<int> Grade(ss,SIZE);
CircleList<int> B(qq,5);
cout<<"链表内容:"<<endl;
Grade.Print();
cout<<"长度为:"<<endl;
cout<<Grade.GetLength()<<endl;
cout<<"查找5的位置:"<<endl;
cout<<Grade.Location(5)<<endl;
cout<<"删除第10个位置后的内容:"<<endl;
Grade.Delete(10);
Grade.Print();
cout<<"此时长度为:"<<endl;
cout<<Grade.GetLength()<<endl;
cout<<"在第9个位置插入11的内容:"<<endl;
Grade.Insert(9,11);
Grade.Print();
cout<<"排序后:"<<endl;
Grade.sort();
Grade.Print();
Grade.Connect(B);
cout<<"连接后:"<<endl;
Grade.Print();
return 0;
}
数据结构-线性表-单循环链表(使用尾指针)(c++)的更多相关文章
- C语言 严蔚敏数据结构 线性表之链表实现
博主最近在考成都大学皇家计算机科学与技术专业,复习专业课数据结构,正好学习到线性结构中的线性表用链表这种存储结构来实现. 首先,数据结构包括1.数据的操作2.逻辑结构3.存储结构(数据结构三要素. 直 ...
- C数据结构 : 线性表 与 链表
一.线性表 一般表现为数组,使用一组地址连续的存储单元依次存储数据元素,如图: 它具有如下特点: 长度固定,必须在分配内存之前确定数组的长度. 存储空间连续,即允许元素的随机访问. 存储密度大,内存中 ...
- [数据结构-线性表1.2] 链表与 LinkedList<T>(.NET 源码学习)
[数据结构-线性表1.2] 链表与 LinkedList<T> [注:本篇文章源码内容较少,分析度较浅,请酌情选择阅读] 关键词:链表(数据结构) C#中的链表(源码) 可空类 ...
- [从今天开始修炼数据结构]线性表及其实现以及实现有Itertor的ArrayList和LinkedList
一.线性表 1,什么是线性表 线性表就是零个或多个数据元素的有限序列.线性表中的每个元素只能有零个或一个前驱元素,零个或一个后继元素.在较复杂的线性表中,一个数据元素可以由若干个数据项组成.比如牵手排 ...
- Java数据结构-线性表之单链表LinkedList
线性表的链式存储结构,也称之为链式表,链表:链表的存储单元能够连续也能够不连续. 链表中的节点包括数据域和指针域.数据域为存储数据元素信息的域,指针域为存储直接后继位置(一般称为指针)的域. 注意一个 ...
- C# 数据结构 线性表(顺序表 链表 IList 数组)
线性表 线性表是最简单.最基本.最常用的数据结构.数据元素 1 对 1的关系,这种关系是位置关系. 特点 (1)第一个元素和最后一个元素前后是没有数据元素,线性表中剩下的元素是近邻的,前后都有元素. ...
- c数据结构 -- 线性表之 顺序存储结构 于 链式存储结构 (单链表)
线性表 定义:线性表是具有相同特性的数据元素的一个有限序列 类型: 1:顺序存储结构 定义:把逻辑上相邻的数据元素存储在物理上相邻的存储单元中的存储结构 算法: #include <stdio. ...
- [置顶] ※数据结构※→☆线性表结构(list)☆============单向链表结构(list single)(二)
单向链表(单链表)是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始:链表是使用指针进行构造的列表:又称为结点列表,因为链表是由一个个结点组装起来的:其中每个结点都有指 ...
- [置顶] ※数据结构※→☆线性表结构(queue)☆============优先队列 链式存储结构(queue priority list)(十二)
优先队列(priority queue) 普通的队列是一种先进先出的数据结构,元素在队列尾追加,而从队列头删除.在优先队列中,元素被赋予优先级.当访问元素时,具有最高优先级的元素最先删除.优先队列具有 ...
- 数据结构-线性表的链式存储相关算法(C语言实现)
链表的简单介绍 为什么需要线性链表 当然是为了克服顺序表的缺点,在顺序表中,做插入和删除操作时,需要大量的移动元素,导致效率下降. 线性链表的分类 按照链接方式: 按照实现角度: 线性链表的创建和简单 ...
随机推荐
- 行行AI人才直播第11期:墨尔本大学数据科学高级讲师-宫明明《机器学习:从统计到因果,人工智能的发展之路》
行行AI人才是博客园和顺顺智慧共同运营的AI行业人才全生命周期服务平台. 马克斯·普朗克智能系统中心主任曾在国际数学家大会进行了题为 From Statistical to Causal Learni ...
- JavaScript代码片段精选
今天,我在职坐标的微信公众号里面看到了关于 JavaScript代码片段精选 的 微信软文.在实际开发中,我们经常会使用的JS来实现某些功能.今天,就在此总结一下. 1.浮点数取整 const x ...
- 1.0 Python 标准输入与输出
python 是一种高级.面向对象.通用的编程语言,由Guido van Rossum发明,于1991年首次发布.python 的设计哲学强调代码的可读性和简洁性,同时也非常适合于大型项目的开发.py ...
- Ubuntu20.04 下编译和运行 FreeSWITCH的问题汇总
1. Ubuntu20.04 下编译和运行 FreeSWITCH的问题汇总 1.1. 环境 Ubuntu20.04.2 LTS (Linux 5.4.0-152-generic x86_64 GNU/ ...
- Vue项目打包后放到SpringBoot项目里注意点
- android webview调用js(vue)问题记录
这几天和别人对接移动端,安卓平台,我们这边输出vue界面,安卓方反馈轮询的时候调用不到,具体原因也定位不到,只能确定前端这边没几句代码,应该没有问题,因此决定自己下载个android studio写个 ...
- 为什么要使用API接口,他能带来哪些便利
API接口是程序员进行应用程序开发时不可或缺的工具之一.以下是使用API接口的一些优点: 数据交换:使用API接口可以使不同的应用程序.网站或服务之间交换数据更为便捷,减少人工输入数据的时间和风险. ...
- jQuery默认选中下拉框的某个值
$("#quaterSelect").val("0");//id为quaterSelect的下拉框默认选中value是0的option选项
- Solution -「SP 106」BINSTIRL
Description Link. 求 \(\begin{Bmatrix}n \\ m\end{Bmatrix}\bmod2\) Solution 求 \[\begin{aligned} \begin ...
- Solution -「CCPC Winter Camp Day 6 A」Convolution
Description Link. 给定一个数列 \(\sf a_1,a_2,....a_n\),请求出下面这个结果在模 \(\sf 998244353\) 下的答案. \[\sum_{i=1}^{n ...