数据结构-线性表-单循环链表(使用尾指针)(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语言实现)
链表的简单介绍 为什么需要线性链表 当然是为了克服顺序表的缺点,在顺序表中,做插入和删除操作时,需要大量的移动元素,导致效率下降. 线性链表的分类 按照链接方式: 按照实现角度: 线性链表的创建和简单 ...
随机推荐
- Linux实现双击自动安装deb文件
在Linux中,有几个常用的软件可以实现双击自动安装.deb文件的功能.以下是一些推荐的软件: 1. GDebi:GDebi是一个轻量级的图形化工具,专门用于安装.deb文件.它可以解决依赖关系,并提 ...
- zabbix 使用监控项原型(自动发现规则)
以kafka为例,需要先对 topic-parttion 做发现,脚本如下 cat topic_parttion_discovery.py #!/usr/bin/env python import j ...
- 解密Prompt系列12. LLM Agent零微调范式 ReAct & Self Ask
前三章我们分别介绍了思维链的使用,原理和在小模型上的使用.这一章我们正式进入应用层面,聊聊如何把思维链和工具使用结合得到人工智能代理. 要回答我们为什么需要AI代理?代理可以解决哪些问题?可以有以下两 ...
- C/C++八大排序
排序 排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存. 按照难易程度排序,八大排序算法可以从简单到复杂 ...
- 基于python tornado实现的简易图床
基于python tornado实现的简易图床 项目地址 因为买了阿里/腾讯的云服务器,但是使用云存储还需要收费,又加上家里正好有一台nas,又加上闲的没事,所以搞了一个小脚本 这个项目主要功能是为t ...
- 【pytorch】目标检测:新手也能彻底搞懂的YOLOv5详解
YOLOv5是Glenn Jocher等人研发,它是Ultralytics公司的开源项目.YOLOv5根据参数量分为了n.s.m.l.x五种类型,其参数量依次上升,当然了其效果也是越来越好.从2020 ...
- 《SQLi-Labs》01. Less 1~5
@ 目录 前言 索引 Less-1 题解 原理 Less-2 题解 Less-3 题解 Less-4 题解 Less-5 题解 原理 sqli.开启新坑. 前言 对于新手,为了更加直观的看到 sql ...
- 《SQL与数据库基础》06. 函数
目录 函数 字符串函数 数值函数 日期函数 流程函数 本文以 MySQL 为例 函数 函数是指一段可以直接被另一段程序调用的程序或代码. 要查看函数操作的结果,可以使用 SELECT 函数(参数); ...
- CodeForces 1332D Walk on Matrix
题意 \(Bob\)想解决一个问题:一个\(n\cdot m\)的矩阵,从\((1,1)\)出发,只能走右和下,问从\((1,1)\)到\((n,m)\)的最大\(\&\)和 他的算法如下(\ ...
- 使用RabbitMQ最终一致性库存解锁
一.基本介绍 ①延时队列(实现定时任务) 场景:比如未付款订单,超过一定时间后,系统自动取消订单并释放占有物品. 常用解决方案: spring的 schedule定时任务轮询数据库:缺点:消耗系统内存 ...