数据结构—带头结点的单循环链表

2023-05-16

1.基本操作

  • 循环链表的特点是最后一个元素的指针域指向头结点。

  • 因此对于循环链表的初始化(设表的头结点是L, 不再是L->next=NULL,而是L->next=L。循环链表为空时,头结点的下一个结点依然是头结点本身。因此但虚幻链表的初始化如下:
//初始化 
int InitList(LinkList &L)
{
	L=new LNode;
	L->next=L;   //非循环链表的初始化是头指针的指针域置空 L->next=NULL 
	return 1;
}
  • 从循环链表中的任何一个结点的位置都可以找到其他所有结点,而单链表做不到;
  • 循环链表中没有明显的尾端,如何避免死循环?
  • 循环条件:
    • p!=NULL  -—>  p!=L                    
    • p->next!=NULL ——>  p->next!=L
  • 所以根据循环链表的特点,判断循环链表是否为空时,只需判断头结点的下一个结点是否是头结点即可:
//判断链表是否为空
int ListEmpty(LinkList L)
{
	if(L->next==L)
	{
		return 1;//空 
	}
	else
	{
		return 0;//非空 
	}
}
  • 从头检查每一个结点,若当前结点不是头结点,则链表长度加1,由此可计算链表的长度:
//获取链表长度
int ListLength(LinkList L)
{
	int length=0;
	LNode *p;
	p=L->next;
	while(p!=L)
	{	//当p不是头结点时,链表长度加1 
		p=p->next;
		length++;
	}
	return length;
} 
  • 遍历链表
//遍历链表
void TraveList(LinkList L)
{
	LNode *p;
	p=L->next;
	printf("遍历链表:\n");
	while(p!=L)
        {      //当p不是头结点时,输出元素值 
		printf("%d ",p->data);
		p=p->next;
	}
	printf("\n");
} 
  • 使用头插法和尾插法创建单循环链表的方法和创建一般单链表的操作一样,区别在于建立空链表的语句不同。一般单链表是L->next=NULL,而单循环链表是L->next=L。
  • 头插法
//头插法创建单循环链表
void CreateList1(LinkList &L,int n)
{
	//创建长度为n的单循环链表 
	L=new LNode;
	L->next=L;
	printf("请输入链表元素值:\n");
	for(int i=n;i>0;--i)
        {
		printf("请输入第%d个元素的值:",i);
		LNode *p;
		p=new LNode;//生成新结点
		scanf("%d",&p->data);
		p->next=L->next;;
		L->next=p; 
	}
} 
  • 尾插法
//尾插法创建单循环链表
void CreateList2(LinkList &L,int n)
{
	L=new LNode;
	L->next=L;
	struct LNode *r;
	r=L;
	for(int i=0;i<n;i++)
    {
		printf("请输入第%d个元素的值:",i+1);
		LNode *p;
		p=new LNode;
		scanf("%d",&p->data);
		p->next=L;
		r->next=p;
		r=p;
	}
} 
  • 单循环链表的删除操作和一般单链表的操作时一样的。要注意的是单循环链表的插入操作:
//单循环链表的插入操作
int ListInsert(LinkList &L,int location,int &e)
{
    //在L的location位置插入元素e
     LNode *p;
     p=L;
     int j=0;
     while(p->next!=L&&j<location-1)
     {
       //注意:由于p初始时指向头结点,所以循环的条件是 p->next!=L,而不是 p!=L 
         p=p->next;                      
         j++;
     }
     if(p==L||j>location-1)
     {
         return 0;
     }
     LNode *s;
     s=new LNode;
     s->data=e;
     s->next=p->next;
     p->next=s;
     return 1;
} 
  • 删除操作
//单循环链表的删除操作
int ListDelete(LinkList &L,int location,int &e)
{
	//删除L中location位置的元素,并用e返回其值
	 LNode *p;
	 p=L;
	 int j=0;
	 while(p->next!=L&&j<location-1)
	 {
	 	p=p->next;
	 	j++;
	 }
	 if(p==L||j>location-1)
	 {
	 	return 0;
	 }
	 
	 LNode *q;
	 q=new LNode;
	 q=p->next;
	 p->next=q->next;
	 e=q->data;
	 delete q;
	 return 1;
} 

2.代码实现

  • man.cpp
#include<iostream>

using namespace std;

//存储结构 
typedef struct LNode 
{
	int data;
	struct LNode *next;
}LNode, *LinkList;

//初始化 
int InitList(LinkList &L) 
{
	L = new LNode;
	L->next = L;       //非循环链表的初始化是头指针的指针域置空 L->next=NULL 
	
	return 1;
}

// 判断链表是否为空
int ListEmpty(LinkList L)
{
	if (L->next == L)
	{
		return 1;   // 空 
	}
	else 
	{
		return 0;  // 非空 
	}
}

// 获取链表长度
int ListLength(LinkList L) 
{
	int length = 0;
	LNode *p;
	p = L->next;
	while (p != L)
	{                  //当p不是头结点时,链表长度加1 
		p = p->next;
		length++;
	}
	
	return length;
}

// 遍历链表
void TraveList(LinkList L) 
{
	LNode *p;
	p = L->next;
	
	printf("遍历链表:\n");
	while (p != L) 
	{                             //当p不是头结点时,输出元素值 
		printf("%d ", p->data);
		p = p->next;
	}
	
	printf("\n");
}

// 头插法创建单循环链表
void CreateList1(LinkList &L, int n) 
{
	//创建长度为n的单循环链表 
	L = new LNode;
	L->next = L;
	
	printf("请输入链表元素值:\n");
	for (int i = n; i > 0; --i)
	{
		printf("请输入第%d个元素的值:", i);
		struct LNode *p;
		p = new LNode;//生成新结点
		scanf("%d", &p->data);
		p->next = L->next;;
		L->next = p;
	}
}

// 尾插法创建单循环链表
void CreateList2(LinkList &L, int n) 
{
	L = new LNode;
	L->next = L;
	struct LNode *r;
	r = L;
	
	printf("请输入链表元素值:\n");
	for (int i = 0; i < n; i++) 
	{
		printf("请输入第%d个元素的值:", i + 1);
		LNode *p;
		p = new LNode;
		scanf("%d", &p->data);
		p->next = L;
		r->next = p;
		r = p;
	}
}

//单循环链表的插入操作
int ListInsert(LinkList &L, int location, int &e) 
{
	//在L的location位置插入元素e
	LNode *p;
	p = L;
	int j = 0;
	
	while (p->next != L && j < location - 1) 
	{
		//注意:由于p初始时指向头结点,所以训话的条件是 p->next!=L 
		//而不是 p!=L 
		p = p->next;
		j++;
	}
	if (p == L || j > location - 1) 
	{
		return 0;
	}

	LNode *s;
	s = new LNode;
	s->data = e;
	s->next = p->next;
	p->next = s;
	
	return 1;
}

//单循环链表的删除操作
int ListDelete(LinkList &L, int location, int &e) 
{
	//删除L中location位置的元素,并用e返回其值
	LNode *p;
	p = L;
	int j = 0;
	
	while (p->next != L && j < location - 1) 
	{
		p = p->next;
		j++;
	}
	if (p == L || j > location - 1) 
	{
		return 0;
	}
	
	LNode *q;
	//q = new LNode;
	q = p->next;
	p->next = q->next;
	e = q->data;
	
	delete q;
	
	return 1;
}

int main() 
{
	LinkList L;

	if (InitList(L)) 
	{
		printf("初始化成功!\n");
	}
	else 
	{
		printf("初始化失败!\n");
	}

	if (ListEmpty(L)) 
	{
		printf("当前链表为空.\n");
	}
	else 
	{
		printf("链表非空.\n");
	}

	printf("请输入链表长度:");
	int n;
	scanf("%d", &n);
	CreateList2(L, n);

	if (ListEmpty(L)) 
	{
		printf("当前链表为空.\n");
	}
	else 
	{
		printf("链表非空.\n");
	}

	printf("当前链表长度是:%d\n", ListLength(L));
	TraveList(L);

	printf("请输入插入位置和值:\n");
	int location, e;
	scanf("%d,%d", &location, &e);
	if (ListInsert(L, location, e)) 
	{
		printf("插入成功\n");
	}
	else 
	{
		printf("插入失败\n");
	}
	TraveList(L);

	printf("请输入删除元素的位置:\n");
	int e1, location1;
	scanf("%d", &location1);
	if (ListDelete(L, location1, e1)) 
	{
		printf("删除成功\n");
		printf("删除的元素值为:%d\n", e1);
	}
	else 
	{
		printf("删除失败\n");
	}
	TraveList(L);

	system("pause");

	return 0;
}
  • 运行结果

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

数据结构—带头结点的单循环链表 的相关文章

随机推荐

  • 关于C++流的缓冲区的讨论

    现在来讨论一下关于C 43 43 的输入输出流的缓冲区问题 一般 C 43 43 我们使用输出流cout都会用到endl这个操纵符 是吧 C 43 43 里有几个可以来控制缓冲区刷新的操纵符 endl flush ends unitbuf
  • Ubuntu(20.4)新装系统应该做的几件事

    一 配置root密码 sudo passwd 二 修改主机名 hostname 主机名 hostname 是在操作系统的安装过程中设置的 xff0c 或者在创建虚拟机时动态分配给虚拟机的 本指南说明了如何在Ubuntu 20 04上设置或更
  • Linux作为主力机--Manjaro 22.0.4

    1 对操作系统的看法 个人是做软件开发的 xff0c 已经使用Manjaro作为主力机两年多了 xff0c 真的是特别喜欢这个操作系统 经过两年的打磨 xff0c 个人16年的惠普老电脑加上这个Manjaro 22 0 4操作系统完全可以再
  • Git回退代码到某次commit

    前言 工作中 xff0c Git的使用越来越频繁 除了最常用的clone add commit push pull等命令 xff1b 还有回退命令reset 这一篇博客就记录一下该回退命令的简单使用 场景 因为公司开发过程中 xff0c 处
  • java位运算(一),了解二进制与八进制,十进制以及16进制的转换

    先放上0 15的各种进制转换码 xff0c 方便做个简单的比较 0 15 十进制 0 1 2 3 4 5 6 7 8 9 10 1112131415二进制 xff08 binary xff09 0 1 10 11 100 101 110 1
  • matlab中interp2双线性插值算法的实现原理及使用python简单实现双线性插值interp2算法

    双线性插值算法基本原理 双线性插值算法的基本原理 xff1a 图1 双线性插值示意图 图中绿色的点P为待插值得到的点 xff0c 对点P进行插值需要用到Q11 x1 y1 Q12 x1 y2 Q21 x2 y1 Q22 x2 y2 的值 x
  • Linux 运行shell文件,出现 $‘\r‘: command not found

    运行编写的shell脚本时 xff0c 出现了 r command not found 这样的错误提示 报错的原因是我们在windows系统操作时 xff0c 编辑器里的换行符是 r n xff0c 而Linux上为 n xff0c 两个系
  • [Swoole] 在Ubuntu下安装、快速开始

    本文主要讲述在 Ubuntu 下编译安装 Swoole xff0c 并根据官方文档给出的demo进行了测试和搬运 xff0c 包括 xff1a TCP服务器 UDP服务器 HTTP服务器 WebSocket服务器 异步客户端 定时器和协程相
  • C++ 快速幂取模算法

    快速求 b p k的值 1 模运算与乘法的性质 乘积取模可以在乘之前先取模 x y d 61 x d y d d 比如 xff1a a a c 61 a c a c c 2 本题公式 当 b为偶数时 xff1a ab mod c 61 a2
  • [Python] socket实现TFTP上传和下载

    Python socket实现TFTP上传和下载 一 说明二 TFTP协议介绍 xff08 参考网络 xff0c 详情可搜索 xff09 2 1 特点 2 2 TFTP下载过程分析 xff1a 2 3 TFTP操作码与数据格式 xff1a
  • [Python] 通过采集两万条数据,对《无名之辈》影评分析

    一 说明 本文主要讲述采集猫眼电影用户评论进行分析 xff0c 相关爬虫采集程序可以爬取多个电影评论 运行环境 xff1a Win10 Python3 5 分析工具 xff1a jieba wordcloud pyecharts matpl
  • [Python] 用python做一个游戏辅助脚本,完整思路

    一 说明 简述 xff1a 本文将以4399小游戏 宠物连连看经典版2 作为测试案例 xff0c 通过识别小图标 xff0c 模拟鼠标点击 xff0c 快速完成配对 对于有兴趣学习游戏脚本的同学有一定的帮助 运行环境 xff1a Win10
  • cp命令 复制多个目录/文件夹下文件到指定目录

    可以使用cp命令的通配符和递归选项来复制多个目录下多个文件夹下的文件到指定目录 如果目标目录不存在 xff0c 可以使用 mkdir p命令来创建目录 p 选项表示递归创建目录 xff0c 如果目录已经存在 xff0c 则不会报错 例如 x
  • 网络安全传输系统(3)—OpenSSL加密传输

    1 基本介绍 1 1 未加密传输的安全弊端 如果在网络传输中没有加密 xff0c 就是以明文传输 传输的数据可以被抓包软件直接截获 xff0c 并能读取里面的数据 1 2 加密基本原理 对称加密 xff1a 对称加密指的就是加密和解密使用同
  • 网络安全传输系统(4)—线程池优化

    服务器单发模式 初始化 gt 等待连接 gt 处理请求 gt 关闭连接 gt 再次等待连接服务器并发模式 初始化 gt 等待连接 gt 交给子进程处理请求 gt 再次等待连接单发服务器不能同时处理多个客户端请求 xff0c 并发服务器则可以
  • 网络安全传输系统(5)—账号管理子系统设计

    1 登录模块设计 输入用户名和密码根据用户名从数据库提取密码比较用户输入密码和数据库提取密码 xff0c 以决定是否登录成功 2 编译客户端程序 arm linux gcc L 008 openssl 1 0 0s install lib
  • C语言实例—一个数如果恰好等于它的因子之和,这个数就称为完数。(gcc编译)

    1 题目 一个数如果恰好等于它的因子之和 xff0c 这个数就称为完数 例如 xff0c 6的因子是1 xff0c 2 xff0c 3 xff0c 而6 61 1 43 2 43 3 xff0c 因此6为完数 编程序找出1000之内所有的完
  • C语言实例—输入两个正整数m和n,求其最大公约数和最小公倍数(gcc 编译)。

    1 辗转相除法 辗转相除法是古希腊求两个正整数的最大公约数的 xff0c 也叫欧几里德算法 xff0c 其方法是用较大的数除以较小的数 xff0c 上面较小的除数和得出的余数构成新的一对数 xff0c 继续做上面的除法 xff0c 直到出现
  • Linux线程详解

    并行和并发的区别 1 并发 concurrency xff1a 在操作系统 中 xff0c 是指一个时间段中有几个程序都处于已启动运行到运行完毕之间 xff0c 且这几个程序都是在同一个处理机上运行 其中两种并发关系分别是同步 和互斥 xf
  • 数据结构—带头结点的单循环链表

    1 基本操作 循环链表的特点是最后一个元素的指针域指向头结点 因此对于循环链表的初始化 xff08 设表的头结点是L xff0c 不再是L gt next 61 NULL xff0c 而是L gt next 61 L 循环链表为空时 xff