单循环链表

说明

单循环链表和单链表(参考单链表)大致一样,只是尾结点要指向头结点,本文是使用尾结点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. MybatisPlus的各种查询方法

    MybatisPlus的各种查询方法 合并转载于https://my.oschina.net/u/241218/blog/1838534/和https://my.oschina.net/u/24275 ...

  2. 面霸的自我修养:Java线程专题

    王有志,一个分享硬核Java技术的互金摸鱼侠加入Java人的提桶跑路群:共同富裕的Java人 平时我在网上冲浪的时候,收集了不少八股文和面试文,内容虽然多,但质量上良莠不齐,主打一个不假思索的互相抄, ...

  3. .NET for Apache Spark 入门演练

    .NET for Apache Spark 入门演练 微软官方文档: .NET for Apache Spark 入门 | Microsoft Learn 注意:由于本次在windows平台下进行演练 ...

  4. C++(继承)

    继承 struct Person { int age; int sex; }; struct Teacher { int age; int sex; int level; int classId; } ...

  5. 《敏捷无敌之DevOps时代》读后感

    背景: 2020年基于我司业务形态,我开始实行敏捷项目管理.以敏捷为道,Scrum为法,迭代为术,禅道作器,大张旗鼓的搞了2年敏捷开发.随着时间推移,问题出现在2022年,当时我们已经完全按照Scru ...

  6. SQLServer 数据库 Money 和 Float 类型运算的奇怪显现

    SQLServer 数据库 Money和 Float类型运算的奇怪显现 1.1 背景 1.2 场景描述 1.3 原因及解决办法 1.1 背景 最近在做一个优化的项目 1.2 场景描述 DECLARE ...

  7. openlayers动态添加自定义div图层 具有筛选功能 和浮窗

    https://blog.csdn.net/weixin_43863505/article/details/119493664

  8. Windows平台的JDK安装及IDEA配置JDK的过程

    1.下载安装包 jdk-8u201-windows-x64.exe,即jdk1.8.0_201 链接:https://pan.baidu.com/s/1WYaTlProtHkC_KyMHIUBxQ?p ...

  9. 学习JavaScript的路径

    学习JavaScript的路径可以按照以下步骤进行: 了解基本概念:首先学习JavaScript的基本概念,包括变量.数据类型.运算符.数组.对象.循环和条件语句等.可以通过阅读相关的教材.在线课程或 ...

  10. crontab定时任务不执行的一些原因总结

    参考博文地址: https://www.jb51.net/article/154290.htm声明:本文章是在以上地址博文基础上进行整理学习,如有侵权,请联系博主删除,感谢知识共享,一起进步,加油鸭 ...