数据结构荣誉课---第一次实验解题报告

Posted qq_52090648

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构荣誉课---第一次实验解题报告相关的知识,希望对你有一定的参考价值。

一,重复计数

题目

在一个有限的正整数序列中,有些数会多次重复出现。请你统计每个数的出现次数,然后按数字在序列中第一次出现的位置顺序输出数及其次数。
输出格式:
若干行,每行两个用一个空格隔开的数,第一个是数列中出现的数,第二个是该数在序列中出现的次数。

输入样例:
在这里给出一组输入。例如:
在这里插入图片描述

输出样例:
在这里给出相应的输出。例如:
在这里插入图片描述

解题思路

用了O(n^2)的方法,在两个平台上都满分通过了,所以只写了这个方法的解题思路。

  • 开辟两个长度为n的数组,一个记录读入的数据,另一个所有元素初始化为0,记录读入的数据是不是第一次出现,如果不是第一次出现,将相应的0改为1。
  • 初始化一个变量count为1,数字重复出现,则count++,循环结束时将count打印出来,再次初始化为1,为下一个数据的统计频率做准备。

代码

#include<stdio.h>
#include<stdlib.h>
int main() {
	int N;
	int a[50001], b[50001] = { 0 };
	int count=1, i, j;
	scanf("%d", &N);
	for (i = 0; i < N; i++) {
		scanf("%d", &a[i]);
	}
	for (i = 0; i < N; i++) {
		if (b[i]==0) {
			count = 1;//初始化
			for (j = i + 1; j < N; j++) {
				if (a[i] == a[j]) {
					b[j] = 1;//标记出现过的数据
					count++;//统计频率
				}
			}
			printf("%d %d\\n", a[i], count);
		}
	}
}

二,报数游戏

题目

n个人围成一圈,从1开始依次编号,做报数游戏。 现指定从第1个人开始报数,报数到第m个人时,该人出圈,然后从其下一个人重新开始报数,仍是报数到第m个人出圈,如此重复下去,直到所有人都出圈。总人数不足m时将循环报数。请输出所有人出圈的顺序。
输入格式:
一行,两个整数n和m。n表示游戏的人数,m表示报数出圈的数字,1≤n≤50000,1≤m≤100.

输出格式:
一行,n个用空格分隔的整数,表示所有人出圈的顺序
输入样例:
在这里给出一组输入。例如:
在这里插入图片描述

输出样例:
在这里插入图片描述

解题思路

  • 这个题是约瑟夫环问题,比较简单。
  • 注意当数到第n个人时将i重置为0.
  • 老师说采用链表结构会更高效,但我还没有试。
 if (i == n) {
            i = 0;  //从头开始数
        }

代码

#include <stdio.h>

void left(int* a,int n,int m) {
    int out = 0,count = 0,i = 0;    
    int *p = a;
    int num = 0;
    for(num = 0;num < n;num++) {
        *(a+num) = num+1;//初始化
    } 
    while (out < n-1) {
        if (*(p+i) != 0) {
            count ++;  
        }
        if (count == m) {//数到了第m个人
            count = 0;//将count初始化,重新开始数
            printf("%d ",*(p+i));
            *(p+i) = 0;//将数到的人赋值为0,不计入循环
            out++;  
        }
        i++;
        if (i == n) {
            i = 0;  //从头开始数
        }
    }
    for (num = 0; num < n; num++) {
        if (*(a+num) != 0) {
            printf("%d\\n",*(a+num));//最后剩下的人
        }
    }
}

int main()
{
    long n;
    int m;
    long a[50000] = {0};
    scanf("%d",&n);
    scanf("%d",&m);   
    left(a,n,m);
    return 0;
}

三,算术表达式

题目

任务: 计算算术表达式的值。

算术表达式按中缀给出,以=号结束,包括+,-,/四种运算和(、)分隔符。运算数的范围是非负整数,没有正负符号,小于等于109 。

计算过程中,如果出现除数为0的情况,表达式的结果为”NaN” ; 如果中间结果超出32位有符号整型范围,仍按整型计算,不必特殊处理。 输入保证表达式正确。

输入格式:
一行,包括1个算术表达式。算术表达式的长度小于等于1000。

输出格式:
一行,算术表达式的值 。

输入样例:
在这里给出一组输入。例如:
在这里插入图片描述
输出样例:
在这里给出相应的输出。例如:
在这里插入图片描述

解题思路

  • 优先级的比较:建一个函数,如果是‘(’或’)'相应的x标记为0,如果是‘+’,‘-’相应的x标记为1,如果是‘*’,‘/’相应的x标记为2。
int first(char ch) {
	int x = 0;
	switch (ch) {
	case '(':
		x = 0; break;
	case ')':
		x = 0; break;
	case '+':
		x = 1; break;
	case '-':
		x = 1; break;
	case '*':
		x = 2; break;
	case '/':
		x = 2; break;
	}
	return x;
}
  • 建两个栈,一个存运算符,一个存数字。如果运算符栈的栈顶元素的优先级低于读入运算符的优先级,则将读入运算符进行压栈操作,反之,弹出栈顶元素,调用运算函数,运算结果,然后将运算结果压入数字栈。
  • 在数字栈内存入数据时,需进行将char型数据转换成int型数据的操作。这里开辟了一个数组,如果数字是两位以上的数字,则分开存储。最后用atoll函数将string类型的数据转换为int类型。
  • 还需注意的一个点是题目要求如果中间结果超出32位有符号整型范围,仍按整型计算,不必特殊处理。但我在课上写的时候没有注意看,使用了long long型栈,导致有一个10分的测试点一直过不去。
  • 此代码还有一个问题是如果我只输入一个数字它会输出NaN,试了挺久我也没发现是怎么回事,不影响得分我就没再纠结了,希望有空的大佬能帮我解答一下。

代码

#include<stdio.h>
#include<iostream>
#include<stack>
#include<string>
#include<stdlib.h>
#define maxsize 1001
using namespace std;
stack<char> s1;
stack<int> s2;
int first(char ch);
int yunsuan(int a, int b, char ch);
void result(char str[]);
int first(char ch) {
	int x = 0;
	switch (ch) {
	case '(':
		x = 0; break;
	case ')':
		x = 0; break;
	case '+':
		x = 1; break;
	case '-':
		x = 1; break;
	case '*':
		x = 2; break;
	case '/':
		x = 2; break;
	}
	return x;
}
int yunsuan(int a, int b, char ch)
{
	int c = 0;
	switch (ch)
	{
	case '+':
		c = a + b;
		break;
	case '-':
		c = a - b;
		break;
	case '*':
		c = a * b;
		break;
	case '/':
		if (b == 0)
		{
			cout << "NaN" << endl;
			exit(0);
		}
		else
			c = a / b;
		break;
	}
	return c;
}
void result(char str[])
{
	char num[maxsize];
	char top1;
	int f, c, get1, get2;
	int j, i;
	for (i = 0; str[i] != '='; i++)
	{
		switch (str[i])
		{
		case '(':
			s1.push(str[i]);
			break;
		case '+':
		case '-':
		case '*':
		case '/':
			if ((s1.empty()))
				s1.push(str[i]);
			else if (first(str[i]) > first(s1.top()))
				s1.push(str[i]);
			else {
				while (!s1.empty() && first(str[i]) <= first(s1.top()) && s1.top() != '(')
				{
					get1 = s2.top();
					s2.pop();
					get2 = s2.top();
					s2.pop();
					top1 = s1.top();
					c = yunsuan(get2, get1, top1);
					s1.pop();
					s2.push(c);
				}
				s1.push(str[i]);
			}
			break;
		case ')':
			while (s1.top() != '(')
			{
				get1 = s2.top();
				s2.pop();
				get2 = s2.top();
				s2.pop();
				top1 = s1.top();
				s1.pop();
				c = yunsuan(get2, get1, top1);
				s2.push(c);
			}
			s1.pop();
			break;
		default:
			j = 0;
			do
			{
				num[j++] = str[i];
				i++;
			} while (str[i] >= '0' && str[i] <= '9');
			num[j] = '\\0';
			f = atoll(num);
			i--;
			s2.push(f);
			break;
		}
	}
	while (!s1.empty())
	{
		get1 = s2.top();
		s2.pop();
		get2 = s2.top();
		s2.pop();
		top1 = s1.top();
		s1.pop();
		c = yunsuan(get2, get1, top1);
		s2.push(c);
	}
	printf("%d", s2.top());
}
int main() {
	char str[maxsize];
	scanf("%s", str);
	result(str);
	return 0;
}

四,最喜爱的序列

题目

小唐这段时间在研究序列。拿来N个整数的序列,他给序列中的每个整数都赋予一个喜爱值。喜爱值也是整数,有正有负,越大表明越喜欢。他想知道,如何从序列中连续取最多m个数,他获得喜爱值最大。1≤N≤500000,1≤m≤N。
输入格式:
第一行是两个整数N,m。分别代表序列中数的个数以及能取的最多个数。

第二行用空格隔开的N个整数,第i个整数Li代表他对第i个数的喜爱值。│Li│≤1000

输出格式:
一行,三个数,表示获得最大喜爱值,及第一个取最大喜爱值的区间。

输入样例:
在这里给出一组输入。例如:
在这里插入图片描述
输出样例:
在这里给出相应的输出。例如:
在这里插入图片描述

解题思路

  • 开辟一个数组,读入数据的同时,记录前n项的和,以便后续计算。
for (int i = 1; i <= N; i++) {
		cin >> array[i];
		array[i] += array[i - 1];//记录前n项的和
	}
  • 使用STL中的deque双端队列,每读取一个元素就和队尾元素进行比较,如果队非空,且当前元素小于队尾元素,就弹出队尾元素,重复以上操作,直到队空或者队尾元素小于当前元素,如果队首元素的编号不在区间内,则弹出队首元素,重复以上操作。
  • 初始化一个变量存储当前区间的元素之和,然后和最大元素之和比较,如果当前区间的元素之和大于最大元素之和,则更新最大元素之和。

代码

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<iostream>
#include<deque>
using namespace std;
deque<int> x;
int main() {
	int N, m, front, rear;
	cin >> N;
	cin >> m;
	int array[500001];
	array[0] = 0;
	for (int i = 1; i <= N; i++) {
		cin >> array[i];
		array[i] += array[i - 1];//记录前n项的和
	}
	int sum = 0;
	while (!x.empty())
		x.pop_back();
		x.push_front(0);
	for (int i = 1; i <= N; i++) {
		while (!x.empty() && array[x.front()] > array[i]) {//判断队列是否为空,弹出大于当前元素的节点的编号
			x.pop_front();
		}
		x.push_front(i);//当前元素的编号入队
		while (!x.empty() && i - x.back() > m) {
			x.pop_back();
		}
		int tmp=array[i] - array[x.back()];
		if (sum < tmp) {//判断是否更新最大值
			sum = tmp;
			front = x.back() + 1;
			rear = i;
		}
	}
	cout<<sum<<" "<<front<<" "<<rear;
	return 0;
}

以上是关于数据结构荣誉课---第一次实验解题报告的主要内容,如果未能解决你的问题,请参考以下文章

数据结构荣誉课---第一次实验解题报告

数据结构荣誉课---第一次实验解题报告

数据结构荣誉课-第一次实验-解题报告

数据结构荣誉课--第三次实验解题报告

数据结构荣誉课--第三次实验解题报告

数据结构荣誉课--第三次实验解题报告