【数据结构与算法——C语言】“链表操作与算法”之“最大节点序号”

1. 实验内容及上机实验所用平台

1.1 实验内容

假设不带头结点的单链表结点类型如下:

struct ListNode
{ int val;
 ListNode *next;
 ListNode(int x):val(x),next(NULL){}
};

根据给定的数据序列构建循环单链表 L,并设计一个算法,求该非空循环单链表 L 中最后一个最大节点的逻辑序号。

输入形式】输入含有 n 个元素的单链表
输出形式】最后一个最大节点的逻辑序号(序号从 1 开始编号)。
样例说明】根据读入数据构建循环单链表

1.2 设计思路

根据输入数据构建一个非空循环单链表 L ,由于此循环单链表不带头结点,所以可以将输入的第 1 个数据作为循环单链表的首结点,方便后续查找和结束。另外用计数器得到每个元素的序号,通过链式查找找到最大的节点,输出其序号。

1.3 实验平台软件

Dev-C++.

2. 数据结构

循环单链表,有指向后继结点的 next 指针,且尾结点的 next 指向首结点。

3. 设计描述与分析

3.1 伪码

输入:字符串 str
输出:最大节点的序号 pre_i

// 将字符串str转化为数组num 
// 利用数组num创建循环单链表 
// 生成首结点first
// 生成结点*pre ← first→next,*max_pre ← pre
while pre != first
    if pre指向的值 ≥ max_pre指向的值
        max__ pre ← pre
        // 保存其序号pre_i
     end if
     pre ← (pre → next)
 end while
return pre_i

3.2 流程图

在这里插入图片描述

3.3 主要代码段

int Find() {	// 找最后一个最大节点的逻辑序号 
	LinkNode *pre = first -> next, *max_pre = pre;
	int i = 1, pre_i = i;	// 初始化元素序号为1,最大结点为第一个元素 
	while (pre != first) {	// 寻找最大结点 
		if (pre -> val >= max_pre -> val) {	// 找到当前最大结点 
			max_pre = pre;	// 将最大结点存下来 
			pre_i = i;	// 将最大结点的序号存下来 
		}
		pre = pre -> next;	// 指针后移 
		i++;	// 结点序号 
	}
	return pre_i;
}

3.4 源代码

需要先在源代码目录下新建 in.txt 文件,在此文件下输入要测试的数据。

注意:数字之间的分隔符是中文的逗号。

#include <iostream>
#include <string> 
using namespace std;

struct LinkNode {	// 不带头结点的单链表结点类型
	int val;
	LinkNode *next;
	LinkNode(int x): val(x), next(NULL) {}
};

class LinkList {
	LinkNode *first;	// 	循环单链表的首结点 
public:
	void CreateList(int a[], int n) {	// 建立循环单链表
		first = new LinkNode(a[0]);
		LinkNode *s, *r = first;	// r为尾结点指针 
		for (int i = 0; i < n; i++) {
			s = new LinkNode(a[i]);	// 创建数据结点s 
			r -> next = s;	// 将 s 结点链接到末尾 
			r = s;
		}
		r -> next = first;	// 构成一个首结点为 first 的循环单链表 
	}
	int Find() {	// 找最后一个最大节点的逻辑序号 
		LinkNode *pre = first -> next, *max_pre = pre;
		int i = 1, pre_i = i;	// 初始化元素序号为1,最大结点为第一个元素 
		while (pre != first) {	// 寻找最大结点 
			if (pre -> val >= max_pre -> val) {	// 找到当前最大结点 
				max_pre = pre;	// 将最大结点存下来 
				pre_i = i;	// 将最大结点的序号存下来 
			}
			pre = pre -> next;	// 指针后移 
			i++;	// 结点序号 
		}
		return pre_i;
	}
};

int main() {
	cout << "\t\t第3题 - 最大节点序号\n\n";
	cout << "---------------------------------------------------\n\n";
	freopen("in.txt", "r", stdin);
	string str;
	while (cin >> str);	// 读取文件数据(当字符串读取) 
	cout << "样例输入:" << str << endl;
	
	string str_temp = ""; 
    int num_temp[1001] = {0}, num[1001] = {0}, cnt_temp = 0, cnt = 0, x = 0;
    bool flag = false;	// 正数
    
    for(int i = 0; i < str.length(); i++) num_temp[cnt_temp++] = str[i] - '0';	// 将字符全部转为数字 
    // 提取字符串中的数字 
    for (int i = 0; i < cnt_temp; i++) {
    	if (num_temp[i] >= 0 && num_temp[i] <= 9) x = x * 10 + num_temp[i];
		else if (num_temp[i] == -3) flag = true;
		else {
			if (flag) {
				x = -x;
				flag = false;
			}
			num[cnt++] = x;
			x = 0;
			i++;
		}
		if (i == cnt_temp - 1) {
			if (flag) {
				x = -x;
				flag = false;
			}
			num[cnt++] = x;
		}
	}
	
	LinkList L;
	L.CreateList(num, cnt);	// 创建循环单链表 
	cout << "\n\n样例输出:";
	cout << L.Find() << endl;
	
	cout << "\n\n"; 
	freopen("CON", "r", stdin);	// 为了可直接查看exe可执行文件,需要将权限返回键盘 
	system("pause"); 
	return 0;
}

4. 调试过程

  1. 测试1
    a) 测试数据用例:9,-1,3,5,7,9,4
    b) 测试数据用例1的特点:有两个最大结点,要输出最后最大结点的序号。
    c) 测试结果:
    在这里插入图片描述

  2. 测试2
    a) 测试数据用例:-8,-6,-10,-1,-8
    b) 测试数据用例2的特点:结点值均是负数。
    c) 测试结果:
    在这里插入图片描述

  3. 测试3
    a) 测试数据用例:0,-6,-10,-1,-8
    b) 测试数据用例3的特点:最大节点在表头。
    c) 测试结果:
    在这里插入图片描述

5. 实验总结

在此次实验中,遇到的问题主要是数据的提取,本来是想设计一个能够自动分割得到数字的程序,但是在分割时发现输入数据的分隔符是中文的逗号,由于中英文两种字符所占字节不同,无法做到统一标准,因此只能根据给定的中文字符进行分割。另外在分割时是用数组存每个单字符装换后的整数,所以在存储上浪费了很大的空间。而在找最大节点序号的程序上就没有什么问题,只要掌握的指针的操作,那么问题就不大。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值