单循环链表

说明

单循环链表和单链表(参考单链表)大致一样,只是尾结点要指向头结点,本文是使用尾结点rear来表示,之所以使用尾指针,是因为如果使用头结点来寻找列表最后一个元素时间复杂度为O(n),如果使用尾结点来寻找列表最后一个元素时间复杂度为O(1)

注意

  1. 第一个元素地址表示:rear->next->next;最后一个元素地址:rear
  2. 头指针的表示,单链表使用front来标识头指针,单循环链表使用rear->next来表示
  3. 单链表使用p->next=NULL判断是否为尾结点,单循环链表使用p==rear判断是否为尾结点

(一)无参构造函数

建立尾结点,使尾结点指针域指向自己,说明链表为空

template<class T>
CircleList<T>::CircleList()
{
rear=new Node<T>;
rear->next=rear;
}

(二)有参构造函数

这里的方法相当于单链表中使用的尾插法,

  1. 为rear开辟空间
  2. 创建头指针Headr,并把rear的地址赋给Headr
  3. 使用for循环将数组依次加入到列表中
  4. 创建一个临时结点temp
  5. 为temp值域赋值,并把其地址赋给rear->next
  6. 修改rear地址
  7. 最后将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;
}

(七)插入

和单链表略有不同

  1. 先判断插入位置是否正确
  2. 然后在插入
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;
}

(八)删除

  1. 获取第i-1位置的地址
  2. q表示第i个元素
  3. 摘链
  4. 释放

如果删除最后一个元素需要单独释放:

  1. 用temp存储最后元素的地址
  2. 让rear指向倒数第二个元素
  3. 摘链,让倒数第二个元素指向头结点
  4. 释放
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;
}
}
}

(十一)连接

  1. 保存b链的头结点
  2. b链的尾指向当前链表的头
  3. 当前链表的尾,指向b链的第一个元素
  4. 修改尾指针
  5. 将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++)的更多相关文章

  1. C语言 严蔚敏数据结构 线性表之链表实现

    博主最近在考成都大学皇家计算机科学与技术专业,复习专业课数据结构,正好学习到线性结构中的线性表用链表这种存储结构来实现. 首先,数据结构包括1.数据的操作2.逻辑结构3.存储结构(数据结构三要素. 直 ...

  2. C数据结构 : 线性表 与 链表

    一.线性表 一般表现为数组,使用一组地址连续的存储单元依次存储数据元素,如图: 它具有如下特点: 长度固定,必须在分配内存之前确定数组的长度. 存储空间连续,即允许元素的随机访问. 存储密度大,内存中 ...

  3. [数据结构-线性表1.2] 链表与 LinkedList<T>(.NET 源码学习)

    [数据结构-线性表1.2] 链表与 LinkedList<T> [注:本篇文章源码内容较少,分析度较浅,请酌情选择阅读] 关键词:链表(数据结构)    C#中的链表(源码)    可空类 ...

  4. [从今天开始修炼数据结构]线性表及其实现以及实现有Itertor的ArrayList和LinkedList

    一.线性表 1,什么是线性表 线性表就是零个或多个数据元素的有限序列.线性表中的每个元素只能有零个或一个前驱元素,零个或一个后继元素.在较复杂的线性表中,一个数据元素可以由若干个数据项组成.比如牵手排 ...

  5. Java数据结构-线性表之单链表LinkedList

    线性表的链式存储结构,也称之为链式表,链表:链表的存储单元能够连续也能够不连续. 链表中的节点包括数据域和指针域.数据域为存储数据元素信息的域,指针域为存储直接后继位置(一般称为指针)的域. 注意一个 ...

  6. C# 数据结构 线性表(顺序表 链表 IList 数组)

    线性表 线性表是最简单.最基本.最常用的数据结构.数据元素 1 对 1的关系,这种关系是位置关系. 特点 (1)第一个元素和最后一个元素前后是没有数据元素,线性表中剩下的元素是近邻的,前后都有元素. ...

  7. c数据结构 -- 线性表之 顺序存储结构 于 链式存储结构 (单链表)

    线性表 定义:线性表是具有相同特性的数据元素的一个有限序列 类型: 1:顺序存储结构 定义:把逻辑上相邻的数据元素存储在物理上相邻的存储单元中的存储结构 算法: #include <stdio. ...

  8. [置顶] ※数据结构※→☆线性表结构(list)☆============单向链表结构(list single)(二)

    单向链表(单链表)是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始:链表是使用指针进行构造的列表:又称为结点列表,因为链表是由一个个结点组装起来的:其中每个结点都有指 ...

  9. [置顶] ※数据结构※→☆线性表结构(queue)☆============优先队列 链式存储结构(queue priority list)(十二)

    优先队列(priority queue) 普通的队列是一种先进先出的数据结构,元素在队列尾追加,而从队列头删除.在优先队列中,元素被赋予优先级.当访问元素时,具有最高优先级的元素最先删除.优先队列具有 ...

  10. 数据结构-线性表的链式存储相关算法(C语言实现)

    链表的简单介绍 为什么需要线性链表 当然是为了克服顺序表的缺点,在顺序表中,做插入和删除操作时,需要大量的移动元素,导致效率下降. 线性链表的分类 按照链接方式: 按照实现角度: 线性链表的创建和简单 ...

随机推荐

  1. Hexo博客yilia主题添加背景音乐 (网易云音乐)

    1. 打开网易云音乐首页,然后搜索你要添加的背景音乐 http://music.163.com/ 2. 搜索到歌曲点击生成外链播放器,进去下一个界面 3. 复制外链播放器的代码 打开yilia主题下的 ...

  2. 2021-11-18 wpf模板

    自定义模板 <ControlTemplate x:Key="ButtonStyle1" TargetType="Button"> <Borde ...

  3. 【go语言】3.1.2 接口的定义和实现

    在 Go 中,接口是一种抽象类型,用来描述其他类型应该有哪些方法.它定义了一组方法,但没有实现.这些方法由其他类型实现. 接口的定义 接口定义的格式如下: type InterfaceName int ...

  4. CSS基础(4)

    目录 1 定位 1.1 为什么需要定位 1.2 定位组成 1.2.1 边偏移(方位名词) 1.2.2 定位模式 (position) 1.3 定位模式介绍 1.3.1 静态定位(static) - 了 ...

  5. dimp V8:[WARNING]login fail, check your username and password, and check the server status

    在进行某个项目的性能测试时,我们选择了达梦8作为使用的数据库.因前期的网络安全问题和考虑到节省成本,我们首先在公司本地服务器上搭建了相应的环境,并生成了用于压力测试的业务数据. 然而,在将数据库迁移到 ...

  6. Ansible快速复习

    本文章是上一篇ansible自动化运维的快速复习以及项目上用到的一些命令,针对长时间未使用ansible,导致命令忘记的同学,帮助快速回忆.详细内容还是看上一章'ansible自动化运维'. 查看版本 ...

  7. Vue的数据更新,页面不更新的解决办法

    可能原因 更新的数据跟源数据不是同一个,即不是同一个引用 解决办法 最稳妥的办法,可通过拿到源数据取索引的方式进行数据的更新,如: 有一个源数据叫:originData 那么如果在更新时,通过this ...

  8. 从头到尾说一次 Spring 事务管理(器)

    事务管理,一个被说烂的也被看烂的话题,还是八股文中的基础股之一.​ 本文会从设计角度,一步步的剖析 Spring 事务管理的设计思路(都会设计事务管理器了,还能玩不转?) 为什么需要事务管理? 先看看 ...

  9. 机器学习-评价指标-AUCROC

    The Area Under the Receiver Operating Characteristic (AUC-ROC) curve is a performance metric commonl ...

  10. 《CTFshow-Web入门》08. Web 71~80

    @ 目录 web71 题解 原理 web72 题解 原理 web73 题解 web74 题解 web75 题解 原理 web76 题解 web77 题解 原理 web78 题解 原理 web79 题解 ...