数据结构-线性表-单循环链表(使用尾指针)(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语言实现)
链表的简单介绍 为什么需要线性链表 当然是为了克服顺序表的缺点,在顺序表中,做插入和删除操作时,需要大量的移动元素,导致效率下降. 线性链表的分类 按照链接方式: 按照实现角度: 线性链表的创建和简单 ...
随机推荐
- Spring Data MongoDB 使用
本文为博主原创,转载请注明出处: Spring Data MongoDB 是 Spring Data 系列的一部分,它提供了与 MongoDB 的集成和操作支持,类似于 JPA 对关系型数据库的支持. ...
- PlayWright(二十一)- Pytest插件报告
1.下载 pytest框架有官方的报告pip install pytest-html 下载成功,那我们怎么使用呢? 2.使用 可以直接在配置文件里使用 在 pytest 配置文件中, 增加 ...
- C#获取文件MD5
什么是MD5? MD5 Message-Digest Algorithm,MD5信息摘要算法.一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于 ...
- Nginx配置Https缺少SSL模块(已解决)
1.Linux下Nginx配置https nginx下载和安装此处就忽略,可自行百度 1.1.配置https 打开nginx配置文件 vim /usr/local/nginx/conf/nginx.c ...
- 2021-7-11 Vue的自定义指令简单实例
获取焦点简单实例,用Vue.directive(ps:指令)定义,命名不要是关键字,用v-加自定义指令名称调用,而内部用钩子函数inserted来实现 <!DOCTYPE html> &l ...
- C#/.net/DotNet/Emgu.CV裁剪照片头像
头像裁剪有利于人脸识别批量照片预处理,安防领域可以快速通过视频定位人脸,进行抓拍,做人脸识别相关功能的可能会应用到人脸裁剪,以下是我在实践中应用的代码,如有需要复制粘贴即可使用. using Emgu ...
- 王道oj/problem13(用递归数楼梯)
网址:http://oj.lgwenda.com/problem/13 思路:用递归写step(int n):return step(n-1)+step(n-2); 停止条件是:n=1为1:n=2为2 ...
- 关于 Task 简单梳理(C#)【并发编程系列】
〇.前言 Task 是微软在 .Net 4.0 时代推出来的,也是微软极力推荐的一种多线程的处理方式. 在 Task 之前有一个高效多线程操作类 ThreadPool,虽然线程池相对于 Thread, ...
- 关于Tensorflow!目标检测预训练模型的迁移学习
前言 关于TF的目标检测迁移学习,我一开始是想通过Tensorflow提供的API,用JS来实现的.但是官方不但没有案例,网上也没有踩坑的博客,加之我又着急要弄水印检测. 于是就在网上看了很多人用 ...
- WPF自定义标题栏
往往原有的标题栏无法满足需求,此时就需要进行自定义标题栏. 重新定义Window的Template 首先,需修改WindowChrome的几个属性 CaptionHeight属性值就是自定义标题栏的高 ...