2023秋数据结构平时实验题目和参考解答¶
第一次上机¶
使用数组实现一个字符串的栈¶
Description
请使用数组实现一个字符串的栈,最大容量为20。输出字符串逆序结果。
注意不要有不必要的输出,比如“请输入字符串”。
Input
一行字符串,长度可能大于最大容量。
Output
输入字符串的逆序输出。
Sample Input 1
HelloWorld!
Sample Output 1
!dlroWolleH
#include <iostream>
#include <cstring>
#include <math.h>
using namespace std;
class Stack {
private:
char stackArray[20];
int top;
public:
Stack():top(-1) {}
void push(char c) {
if (top < 19) {
top++;
stackArray[top] = c;
}
}
char pop() {
if (top >= 0) {
char c = stackArray[top];
top--;
return c;
} else {
return '\0';
}
}
bool isEmpty() const {
return (top == -1);
}
};
int main() {
Stack stack;
char input[66];
cin >> input;
for (int i=0; i < strlen(input); ++i)stack.push(input[i]);
while (!stack.isEmpty()) cout<< stack.pop();
return 0;
}
匹配括号¶
Description
输入一串字符串(长度不超过50),其中有普通的字符与括号组成(包括‘(’、‘)’、‘[’,']'),要求验证括号是否匹配,如果匹配则输出0、否则输出1。
注意不要有不必要的输出,比如“请输入字符串”。
Input
一行字符串。
Output
一个整数表示答案。
Sample Input 1
dfa(sdf)df[dfds(dfd)]
Sample Output 1
0
#include <cstdio>
#include <vector>
using namespace std;
int main()
{
vector<char> container;
char c;
bool flag = true;
while ((c = getchar()) != EOF){
if (c == '(')
container.push_back(')');
else if (c == '[')
container.push_back(']');
else if ((c == ')') || (c == ']'))
{
if (container.back() != c)
{
flag = false;
break;
}
else
container.pop_back();
}
}
printf("%d\n", !(flag && container.empty()) );
return 0;
}
第二次上机¶
通用循环队列¶
Description
请实现一个通用的循环队列。大小上限为10。
向循环队列中插入一次数据,然后取出部分元素,之后再次插入数据。
Input
第1行输入数据类型。
第2行输入第一次插入循环队列的数据个数。
第3行第一次插入循环队列的数据。
第4行输入取出的元素个数。
第5行输入第二次插入循环队列的数据个数。
第6行输入第二次插入循环队列的数据。
Output
最终循环队列中的元素顺序输出。
Sample Input 1
int
6
1 2 3 4 5 6
4
5
7 8 9 10 11
Sample Output 1
5 6 7 8 9 10 11
Hint
浮点数输出忽略多余的0
#include <iostream>
#include <sstream>
template <typename T>
class CircularQueue {
public:
CircularQueue(int maxSize) : maxSize(maxSize), queue(new T[maxSize]), front(0), rear(-1), itemCount(0) {}
~CircularQueue() {
delete[] queue;
}
void insert(const T& data) {
if (itemCount == maxSize) {
// Queue is full, overwrite the front element
front = (front + 1) % maxSize;
}
rear = (rear + 1) % maxSize;
queue[rear] = data;
itemCount++;
}
void remove(int count) {
while (count-- > 0 && itemCount > 0) {
front = (front + 1) % maxSize;
itemCount--;
}
}
void display() {
int count = itemCount;
int index = front;
while (count-- > 0) {
std::cout << queue[index] << " ";
index = (index + 1) % maxSize;
}
std::cout << std::endl;
}
private:
T* queue;
int maxSize;
int front;
int rear;
int itemCount;
};
template <typename T>
void processQueue(CircularQueue<T>& circularQueue) {
int firstInsertCount, secondInsertCount, removeCount;
std::cin >> firstInsertCount;
for (int i = 0; i < firstInsertCount; ++i) {
T data;
std::cin >> data;
circularQueue.insert(data);
}
std::cin >> removeCount;
circularQueue.remove(removeCount);
std::cin >> secondInsertCount;
for (int i = 0; i < secondInsertCount; ++i) {
T data;
std::cin >> data;
circularQueue.insert(data);
}
circularQueue.display();
}
int main() {
std::string dataType;
std::cin >> dataType;
if (dataType == "int" || dataType == "double" || dataType == "float" || dataType == "char" || dataType == "long" || dataType == "short") {
std::istringstream iss(dataType);
if (dataType == "double") {
CircularQueue<double> circularQueue(10);
processQueue(circularQueue);
} else if (dataType == "float") {
CircularQueue<float> circularQueue(10);
processQueue(circularQueue);
} else if (dataType == "char") {
CircularQueue<char> circularQueue(10);
processQueue(circularQueue);
} else if (dataType == "long") {
CircularQueue<long> circularQueue(10);
processQueue(circularQueue);
} else if (dataType == "short") {
CircularQueue<short> circularQueue(10);
processQueue(circularQueue);
} else {
CircularQueue<int> circularQueue(10);
processQueue(circularQueue);
}
} else {
std::cout << "Unsupported data type." << std::endl;
}
return 0;
}
最近的相同字母¶
Description
使用队列寻找二维数组中曼哈顿距离最近的相同字母。
二维数组不大于6*6。
Input
第1行为2个整数,为二维数组的行数和列数。之后按行输入二维数组。
Output
曼哈顿距离最近的字母。
Sample Input 1
3 3
a b c
f e m
c b a
Sample Output 1
b
#include <queue>
#include <iostream>
#include <cmath>
using namespace std;
int n,m,ans,ans1;
int main(){
ans=666666;
cin>>n>>m;
queue<int>Q[26];
char tmp;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cin>>tmp;
Q[tmp-'a'].push(i*m+j);
}
}
vector<int>P;
for(int i=0;i<26;i++)if(Q[i].size()>1)P.push_back(i);
int loc1,loc2,dis;
int loc1x,loc1y,loc2x,loc2y;
for(int i=0;i<P.size();i++){
int ch = P[i];
loc1=Q[ch].front();
Q[ch].pop();
while(!Q[ch].empty()){
loc2=Q[ch].front();
Q[ch].pop();
loc1x=loc1%m;loc1y=loc1/m;
loc2x=loc2%m;loc2y=loc2/m;
dis=abs(loc1x-loc2x)+abs(loc1y-loc2y);
if(dis<ans){
ans=dis;
ans1=ch;
}
loc1=loc2;
}
}
tmp='a'+ans1;
cout<<tmp;
return 0;
}
第三次上机¶
实现循环链表解决约瑟夫问题¶
Description
请使用循环链表解决约瑟夫问题。 约瑟夫问题为n个人围成一个圆圈,首先第1个人从1开始一个人一个人顺时针报数,报到第m个人,令其出列。然后再从下一个人开始,从1顺时针报数,报到第m个人,再令其出列,…,如此下去,直到圆圈中只剩一个人为止。此人即为优胜者。
Input
输入两个整数n和m,n为总人数,m为将被逐出的报数值。
Output
输出一个整数,为最后优胜者序号。
Sample Input 1
8 3
Sample Output 1
7
#include<iostream>
using namespace std;
struct Node {
Node *next;
Node();
int entry;
Node(int item, Node *add_on = NULL);
};
Node::Node( )
{
next = NULL;
}
Node::Node(int item, Node *add_on)
{
entry = item;
next = add_on;
}
enum Error_code{overflow,emptylist,notexist,notfound,success};
class LinkList{
public:
Error_code add(int &item);
Error_code remove(int &item);
Error_code find(int &item,Node *&res_node);
Error_code clear();
Error_code get_front(int &res);
int empty();
int size();
LinkList();
Node *get_next(Node *node);
private:
Node *head;
};
LinkList::LinkList()
{
head=new Node();
head->next=head;
}
Error_code LinkList::add(int &item)
{
Node *new_node = new Node (item, head->next);
if(new_node==NULL)
return overflow;
head->next=new_node;
return success;
}
Error_code LinkList::find(int &item,Node *&res_node)
{
res_node = NULL;
Node *cur=head->next;
while(cur!= head)
{
if(cur->entry==item)
{
res_node=cur;
return success;
}
cur=cur->next;
}
return notfound;
}
Error_code LinkList::remove(int &item)
{
Node *cur=head->next;
Node *prev=NULL;
if(cur==head)
return emptylist;
while(cur!=head)
{
if(cur->entry==item)
{
if(prev==NULL)
{
head->next=cur->next;
delete cur;
cur=NULL;
}
else
{
prev->next=cur->next;
delete cur;
cur=NULL;
}
return success;
}
prev=cur;
cur=cur->next;
}
return notfound;
}
Error_code LinkList::get_front(int &res)
{
if(empty())
{
return emptylist;
}
res=head->next->entry;
return success;
}
Error_code LinkList::clear()
{
Node *cur=head,*pre=NULL;
while(cur)
{
pre=cur;
cur=cur->next;
delete pre;
pre = NULL;
}
head=NULL;
return success ;
}
int LinkList::empty()
{
return (head->next==head);
}
int LinkList::size()
{
int res=0;
Node *cur=head->next;
while(cur!=head)
{
res++;
cur=cur->next;
}
return res;
}
Node *LinkList::get_next(Node *node)
{
if(empty())
{
return NULL;
}
if(node->next==head)
{
return node->next->next;
}
return node->next;
}
int main()
{
int n,m;
cin>>n>>m;
LinkList *ll=new LinkList();
while(n>0)
{
ll->add(n);
n--;
}
int i=1;
Node *cur;
ll->find(i,cur);
while(ll->size()!=1)
{
for(i=1;i<=m-1;i++)
{
cur=ll->get_next(cur);
}
Node *pre=cur;
cur=ll->get_next(cur);
ll->remove(pre->entry);
}
int res;
ll->get_front(res);
cout<<res<<endl;
return 0;
}
第四次上机¶
子集合问题¶
Description
请使用递归的方法,求出n个元素的集合中元素个数为m的子集合个数。
Input
第1行,2个整数,原集合大小n,子集合大小m。
第2行,n个整数,为子集合元素。
Output
输出所有子集合,子集合中元素顺序输出。
Sample Input 1
5 3
1 2 3 4 5
Sample Output 1
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5
#include <iostream>
#include <vector>
using namespace std;
class Solution{
public:
int n;
int k;
int cnt_subset;
Solution() : cnt_subset(0) {}
void DFS(int start, int current_sum){
if (start == n)
{
if (current_sum == k)
++cnt_subset;
}
else
{
if (current_sum + 1 <= k)
DFS(start + 1, current_sum + 1);
else if (current_sum > k)
return;
DFS(start + 1, current_sum);
}
}
int num_subset(int n, int k){
this->n = n;
this->k = k;
DFS(0, 0);
return cnt_subset;
}
};
int main()
{
int n, k;
cin >> n >> k;
cout << Solution().num_subset(n, k) << endl;
return 0;
}
N皇后问题¶
Description
如何在N*N的棋盘上放置N枚棋子,使得任意两个棋子不出现在同一直线上?一共有多少种方法
Input
1个整数,放置棋子个数N
Output
1个整数,可能的放置方法个数。
Sample Input 1
8
Sample Output 1
92
#include <iostream>
#include <vector>
using namespace std;
#define MaxSize 32
class Solution{
public:
vector<int> place;
int n;
int cnt_solution;
Solution(): cnt_solution(0)
{
place.reserve(MaxSize);
}
bool able_place(int row, int col)
{
for (int i = 0; i < row; ++i)
{
if (place[i] == col || abs(place[i] - col) == row - i)
return false;
}
return true;
}
void DFS(int row)
{
if (row == n)
{
++cnt_solution;
}
else
{
for (int col = 0; col < n; ++col)
{
if (able_place(row, col))
{
place[row] = col;
DFS(row + 1);
}
}
}
}
int eight_queen(int n)
{
this->n = n;
DFS(0);
return cnt_solution;
}
};
int main()
{
int n;
cin >> n;
cout << Solution().eight_queen(n) << endl;
return 0;
}
求链表最小值¶
Description
请使用递归的方法,求出int链表中最小值。
Input
第1行1个整数,表示链表中元素个数N。
第2行N个整数,为链表中元素值。
Output
1个整数,为链表中最小值。
Sample Input 1
5
1 2 3 4 5
Sample Output 1
1
#include <iostream>
using namespace std;
struct ListNode {
int val;
ListNode* next;
ListNode(int x) : val(x), next(NULL) {}
};
int findMin(ListNode* head) {
if (head == NULL) {
return 66666666;
}
int minOfRest = findMin(head->next);
return min(head->val, minOfRest);
}
int main() {
int N;
cin >> N;
ListNode* head = NULL;
ListNode* tail = NULL;
for (int i = 0; i < N; ++i) {
int value;
cin >> value;
ListNode* newNode = new ListNode(value);
if (head == NULL) {
head = newNode;
tail = newNode;
} else {
tail->next = newNode;
tail = newNode;
}
}
int result = findMin(head);
cout << result << endl;
while (head != NULL) {
ListNode* temp = head;
head = head->next;
delete temp;
}
return 0;
}
第五次上机¶
迷宫问题¶
Description
请解决迷宫问题,并打印出一条从入口到出口的路径。
前进方向:按照下-右-上-左的顺序。
用使用DFS解答该题。
Input
前8行输入一个8*8的int二维数组,其中0表示通路,1表示墙。
第9行输入入口坐标。
第10行输入出口坐标。
Output
输出8*8int二维数组,其中2表示路径,1表示墙,0表示未经过的点。
Sample Input 1
0 0 1 0 0 0 1 0
0 0 1 0 0 0 1 0
0 0 0 0 1 1 0 0
0 1 1 1 0 0 0 0
0 0 0 1 0 0 0 0
0 1 0 0 0 1 0 0
0 1 1 1 0 1 1 0
1 1 0 0 0 0 0 0
0 0
0 7
Sample Output 1
2 0 1 0 0 0 1 2
2 0 1 0 0 0 1 2
2 0 0 0 1 1 0 2
2 1 1 1 0 0 0 2
2 2 2 1 0 0 0 2
0 1 2 2 2 1 0 2
0 1 1 1 2 1 1 2
1 1 0 0 2 2 2 2
#include <iostream>
#include <vector>
using namespace std;
const int rows = 8;
const int cols = 8;
// 定义迷宫和路径的二维数组
int maze[rows][cols];
int path[rows][cols];
// 定义四个方向的偏移量:下、右、上、左
int dx[] = {1, 0, -1, 0};
int dy[] = {0, 1, 0, -1};
// DFS函数
bool dfs(int x, int y, int ex, int ey) {
// 如果当前位置是出口,返回true
if (x == ex && y == ey) {
path[x][y] = 2; // 标记出口为路径
return true;
}
// 遍历四个方向
for (int i = 0; i < 4; ++i) {
int nx = x + dx[i];
int ny = y + dy[i];
// 判断新位置是否合法
if (nx >= 0 && nx < rows && ny >= 0 && ny < cols && maze[nx][ny] == 0 && path[nx][ny] == 0) {
path[x][y] = 2; // 标记当前位置为路径
if (dfs(nx, ny, ex, ey)) {
return true;
}
path[x][y] = 0; // 如果未找到路径,回溯,将当前位置重新标记为未经过
}
}
return false;
}
int main() {
// 读取迷宫和入口、出口坐标
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
cin >> maze[i][j];
if(maze[i][j]==1)path[i][j]=1;
else path[i][j] = 0; // 初始化路径数组
}
}
int sx, sy, ex, ey;
cin >> sx >> sy >> ex >> ey;
// 调用DFS函数
dfs(sx, sy, ex, ey);
// 输出路径
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
cout << path[i][j] << " ";
}
cout << endl;
}
return 0;
}
滑雪问题¶
Description
Michael喜欢滑雪这并不奇怪,因为滑雪的确很刺激。可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你。Michael想知道载一个区域中最长底滑坡。区域由一个二维数组给出。数组的每个数字代表点的高度。
Input
输入的第一行表示区域的行数n和列数m(1 <= n,m <= 100)。下面是n行,每行有m个整数,代表高度h,0<=h<=10000。 Output
输出最长区域的长度。
Sample Input
5 5
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9
Sample Output
25
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int MAX_N = 100;
int grid[MAX_N][MAX_N];
int dp[MAX_N][MAX_N];
int rows, cols;
// 定义四个方向的偏移量:上、下、左、右
int dx[] = {-1, 1, 0, 0};
int dy[] = {0, 0, -1, 1};
// 递归实现动态规划
int dfs(int x, int y) {
if (dp[x][y] != -1) {
return dp[x][y];
}
dp[x][y] = 1; // 初始化当前点的最长底滑坡为1
for (int i = 0; i < 4; ++i) {
int nx = x + dx[i];
int ny = y + dy[i];
if (nx >= 0 && nx < rows && ny >= 0 && ny < cols && grid[nx][ny] < grid[x][y]) {
dp[x][y] = max(dp[x][y], 1 + dfs(nx, ny));
}
}
return dp[x][y];
}
int main() {
// 读取输入
cin >> rows >> cols;
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
cin >> grid[i][j];
}
}
// 初始化dp数组
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
dp[i][j] = -1;
}
}
int maxLen = 0;
// 遍历每个点,以其为起点进行dfs
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
maxLen = max(maxLen, dfs(i, j));
}
}
cout << maxLen << endl;
return 0;
}