单链表_约瑟夫环的解决(c++)

单链表

链表的概念

链表是一种常用的数据结构,通常用来存储一组同类数据。它与数组最大的不同在于其可以动态的进行内存分配,在需要增加一个元素时,动态的为它申请存储空间,但这样便无法保证元素是连续存储的,链表利用指向下一个节点的指针解决了这个问题。

下图给出了最简单的链表——单链表的结构。
在这里插入图片描述
链表有各种形式,除了单链表外还有双链表,循环链表等。
在这里插入图片描述
图示如下:
在这里插入图片描述
下面我们来讨论单链表。

单链表的存储

每个节点由两部分组成:数据元素本身和指向下一节点的指针。

struct linkNode {
	datatype data;
	linkNode* next;
};

datatype表示任意一种数据类型,第二个成员是指向自身类型的一个指针,这种结构称为自引用结构

单链表的操作

单链表最基本的操作包括:

  • 创建一个单链表
  • 插入一个节点
  • 删除一个节点
  • 访问单链表的每一个节点
创建操作
  • 定义一个单链表
  • 创建一个空的单链表(只含有头结点)
  • 依次从键盘读入数据
  • 键入单链表的表尾
    (具体见单链表实例)
插入操作

在链表中地址为p的节点后面插入另一个元素x:

  • 申请一个节点
  • 将x放入该节点的数据部分
  • 将该接点链接到节点p后面
    在这里插入图片描述
tmp = new linkNode;//创建一个新节点
tmp->data = x;//把x放入新节点的数据成员中
tmp->next = p->next;//把新节点和p的下一节点相连
p->next = tmp;//把p和新节点连接起来
删除操作

将p设为x前面的那个节点,让p的next链绕过x:
在这里插入图片描述
考虑到内存泄露,完整的删除操作应包括:

  • 丛链表中删除节点
  • 回收节点的空间
delPtr = p->next;//保存被删节点的地址
p->next = delPtr->next;//将此节点从链中删除
delete delPtr;//回收被删节点的空间

在上述的描述有一个基本问题:它假定了不论x在什么位置,在它前面总是有一个节点。而链表中的第一个节点前面是没有节点的,因此删除和插入第一个节点就需要特殊处理,但特殊情况通常会给程序设计带来很多麻烦。对于上述问题的解决方案就是引入一个头结点。

头结点不存放数据,只是作为链表的开始标记,位于链表的最前面,指向链表的第一个元素,现在就不在有特殊情况了。

单链表实例

题目: 创建并访问一个带头结点的,存储整型数据的单链表,数据从键盘键入,0作为结束标志。

代码清单:

# include <iostream>

using namespace std;

struct linkRec {
	int data;
	linkRec* next;
};
int main() {
	int x;//存放输入的值
	linkRec* head, * p, * rear;//head为头指针,rear为创建链表的表尾节点
	head = rear = new linkRec;//创建空链表,头结点也是最后一个节点

	cout << "请输入要创建的链表值(以0作为结束标志):"<<endl;
	//创建链表的其他节点
	while (true) {
		cin >> x;
		if (x == 0) break;
		p = new linkRec;//申请一个新的节点
		p->data = x;//将x的值存入新节点
		rear->next = p;//将p链到表尾
		rear = p;//p作为新的表尾
	}
	rear->next = NULL;//设置rear为表尾,其后没有其他节点了

	//读链表
	cout << "链表的内容为" << endl;
	p = head->next;//p指向第一个节点
	while (p != NULL) {
		cout << p->data << '\t';
		p = p->next;
	}
	cout << endl;

	return 0;
}

运行结果:
在这里插入图片描述

约瑟夫环问题

题目: 已知 n 个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围。从编号为 k 的人开始报数,数到 m 的那个人出圈;他的下一个人又从 1 开始报数,数到 m 的那个人又出圈;依此规律重复下去,直到剩余最后一个胜利者。(在此题中令k=1,m=3)

思路:

  • 单循环链表表示n个人围成一圈
  • 模拟报数过程,逐个删除节点

代码清单:

# include <iostream>

using namespace std;

struct node {
	int data;
	node* next;
};

int main() {
	node* head, * p, * q;
	int n, i;

	cout << "\ninput n:";
	cin >> n;

	//建立链表
	head = p = new node;
	p->data = 0;
	for (i = 1; i < n; ++i) {
		q = new node;
		q->data = i;
		p->next = q;
		p = q;
	}
	p->next = head;//收尾相连

	//删除过程
	q = head;//head报数为1
	while (q->next != q) {//表中元素多于一个
		p = q->next;
		q = p->next;//p报数为2,q报数为3
		p->next = q->next;//删除q
		cout << q->data+1 << '\t';//显示被删者的编号
		delete q;//回收被删者的空间
		q = p->next;//让q指向报1的节点
	}
	//打印结果
	cout << "\n最后剩下:" << q->data << endl;

	return 0;
}

运行结果:
在这里插入图片描述
中间一行为删除者编号

  • 8
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值