大二上数据结构第4-5章作业及实验作业个人做法

1-3章作业见之前博客。

最近几章尝试了一下用java完成。

第四章

4-1.逆波兰表达式求值

【问题描述】

根据逆波兰表示法,求表达式的值。有效的运算符包括+,-,*,/。每个运算对象可以是整数,也可以是另一个逆波兰表达式。假设给定逆波兰表达式总是有效的,换句话说,表达式总会得出有效数值且不存在除数为0的情况。其中整数除法只保留整数部分。

【输入形式】

     每个样例是一行,为有效的表达式,每个数字和运算符号之间用“,”隔开
【输出形式】

     表达式的计算结果
【样例输入】

      2,1,+,3,*

【样例输出】

     9 
【样例说明】

    测试数据的文件名为in.txt

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.Stack;

public class Main1 {
    public static void main(String[] args) {
        String filePath="in.txt";
        Stack<Integer> stack=new Stack<>();
        try (BufferedReader br = new BufferedReader(new FileReader(filePath))){     //创建文件读取
            String line;
            line=br.readLine();
            String[] data=line.split(",");                                    //按逗号分隔读取数据
            for (String value:data){                                                //遍历读取数据
                try{
                    int v=Integer.parseInt(value);                                  //若能转换为数字,则入栈
                    stack.push(v);
                }catch (NumberFormatException e){                                   //出现异常,则无法转换为数字,根据符号判断
                    int a,b;
                    switch (value){
                        case "+":
                            a=stack.pop();
                            b=stack.pop();
                            stack.push(b+a);
                            break;
                        case "-":
                            a=stack.pop();
                            b=stack.pop();
                            stack.push(b-a);
                            break;
                        case "*":
                            a=stack.pop();
                            b=stack.pop();
                            stack.push(b*a);
                            break;
                        case "/":
                            a=stack.pop();
                            b=stack.pop();
                            stack.push(b/a);
                            break;
                    }
                }
            }
        } catch (IOException e){
                throw new RuntimeException(e);
        }

        System.out.println(stack.peek());

    }
}

4-2.合并栈操作

【问题描述】

栈是一种具有后进先出的数据结构。可合并栈是支持“merge”操作的栈。三种操作的说明如下:

① push A x:将x插入栈A中。

② pop A:删除栈A的顶部元素。

③ merge A B:合并栈A和B。

其中,“merge A B”操作后栈A包含A和B之前的所有元素,B变为空,新栈中的元素根据先前的进栈时间重新排列,就像在一个栈中重复"push"操作一样。给定两个可合并栈A和B,请执行上述操作。

【输入形式】

     测试用例的第一行包含一个整数n(0<n≤10^5)表示操作个数,接下来的n行每行包含一条指令push、pop或merge,栈元素是32位整数。A和B最初都是空的,并且保证不会对空栈执行pop操作。以n=0表示输入结束。

【输出形式】

     对于每个pop操作,在一行中输出对应的出栈元素。

【样例输入】

9

push A 0

push A 1

push B 3

pop A

push A 2

merge A B

pop A

pop A

pop A
【样例输出】

1

2

3

0

【样例说明】

    测试数据的文件名为in.txt

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;


public class Main2 {
    static int indexA=0;                                                    //A索引为偶数,B索引为奇数,方便在map中添加删除
    static int indexB=1;
    static Stack<Integer> A=new Stack<>();
    static Stack<Integer> B=new Stack<>();
    static LinkedHashMap<Integer,Integer> mapAB=new LinkedHashMap<>();

    public static void main(String[] args) {
        String filePath= "in.txt";
        try(BufferedReader br=new BufferedReader(new FileReader(filePath))){
            String line;
            line=br.readLine();
            while((line=br.readLine())!=null){                              //执行每行指令
                String[] data=line.split(" ");
                operation(data[0],data.length>1?data[1]:"0",data.length>2?data[2]:"0");
            }
        }catch (IOException e){
            throw new RuntimeException(e);
        }
    }
    public static void operation(String op,String name,String n){

        switch (op){                                                        //判断指令类型
            case "push":
                int value=Integer.parseInt(n);
                if (name.equals("A")){                                      //入栈同时为AB共同的map添加元素
                    A.push(value);
                    indexA+=2;
                    mapAB.put(indexA,value);
                }else {
                    B.push(value);
                    indexB+=2;
                    mapAB.put(indexB,value);
                }
                break;
            case "pop":
                if (name.equals("A")){
                    System.out.println(A.pop());                            //出栈同时根据索引从map中删除A或B的数据
                    mapAB.remove(indexA);
                    indexA-=2;
                }else {
                    System.out.println(B.pop());
                    mapAB.remove(indexB);
                    indexB-=2;
                }
                break;
            case "merge":
                A.clear();                                                      //清空A,B
                B.clear();
                if (name.equals("A")){
                    for(Map.Entry<Integer,Integer> entry : mapAB.entrySet()){       //按照map插入顺序为A栈赋值
                        A.push(entry.getValue());
                    }
                }else {
                    for (Map.Entry<Integer, Integer> entry : mapAB.entrySet()) {       //按照map插入顺序为A栈赋值
                        B.push(entry.getValue());
                    }
                }
            case "0":
                break;
        }
    }
}

此做法存在问题,在merge将AB栈合并成一个栈之后,map中数字仍然对应indexA,indexB,于是对合成后的栈进行pop操作时,map中元素不会按照顺序删除,导致如果进行第二次merge合并操作,输出会出现错误,但我没想出改进方法。

4-3.暴力排序

【问题描述】

Beerus需要对n个整数的数组进行排序。他可以同时销毁数组中所有未排序的整数。如果满足以下要求,则整数A[i]是有序的:

① A[i]是数组的第一个元素,或者不小于左边的A[i-1]。

② A[i]是数组的最后一个元素,或者不大于右边的A[i+1]。

例如,在{1,4,5,2,3}中,Beerus可以销毁5和2,该数组将变为{1,4,3}。如果新数组仍未排序,Beerus可以再次进行销毁。

请你帮助Beerus预测最终的数组。采用队列求解。

【输入形式】

     每个测试用例,第一行提供初始数组的大小,该大小应为正且不大于100000。第二行描述具有n个正整数A[1],A[2],⋯,A[n]的数组,其中每个整数A[i]满足1≤A[i]≤100000。

【输出形式】

       对于每个测试用例输出两行,第一行包含一个整数m,它是最终数组的大小。第二行包含m个描述最终数组的整数(每个整数之后空一格)。如果最后一个数组为空,则输出0,第二行为空行。

【样例输入】

     5

     1 2 3 4 5

     5

     5 4 3 2 1

     5

     1 2 3 2 1

【样例输出】

    5

    1 2 3 4 5

    0

    2

    1 2

【样例说明】

    测试数据的文件名为in.txt

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.LinkedList;
import java.util.Queue;

public class Main3 {

    public static void main(String[] args) {
        String filePath="in.txt";
        Queue<Integer> queue=new LinkedList<>();
        try(BufferedReader br=new BufferedReader(new FileReader(filePath))){
            String line;
            line=br.readLine();
            int count=Integer.parseInt(line);           //获取数组长度

            line=br.readLine();
            String[] data=line.split(" ");
            for (String value:data){
                queue.add(Integer.parseInt(value));     //将数组元素加入队列
            }

            do{                                         //不断排序
                count=queue.size();
                queue=violentSort(queue);
            }while (count!=queue.size());

            System.out.println(count);                  //输出
            for (int i=0;i<count;i++){
                System.out.print(queue.poll()+" ");
            }
        }catch (IOException e){
            throw new RuntimeException(e);
        }
    }
    public static Queue<Integer> violentSort(Queue<Integer> q){
        Queue<Integer> queue=new LinkedList<>();
        int prev=0;
        int curr;
        int next=Integer.MAX_VALUE;
        while(!q.isEmpty()){
            curr=q.poll();                              //获取当前元素
            if(!q.isEmpty()){
                next=q.peek();                          //获取下一个元素
            }
            if(prev>curr){                              //判断是否有序
                prev=curr;
                continue;
            }
            if(curr>next){
                prev=curr;
                continue;
            }
            queue.add(curr);                            //新队列中加入有序的值

        }
        return queue;
    }
}

第五章

5-1.团队队列 

【问题描述】

     在团队队列中每个成员都属于一个团队,如果一个成员进入队列,它首先从头到尾搜索队列,以检查它的一些队友(同一队的成员)是否已经在队列中,如果是,它会进入到该团队的后面,如果不是,它会从尾部进入队列并成为新的最后一个成员。成员出队是按常规队列操作,按照出现在队列中的顺序从头到尾进行处理。你的任务是编写一个模拟这样的团队队列的程序。

【输入形式】

     每个测试用例都以团队个数t开始(1≤t≤1000),然后是团队描述,每个描述包含属于团队的成员个数和成员编号列表,成员编号为0到999999之间的整数,一个团队最多可以包含1000个成员。然后是一系列命令,有三种不同的命令:

① ENQUEUE p:成员p进入队列。

② DEQUEUE:队列中第一个成员出来并将其从队列中删除。

③ STOP:当前测试用例结束。

【输出形式】

       对于每个DEQUEUE命令,以单独一行输出出队的成员。

【样例输入】

2

3 101 102 103

3 201 202 203

ENQUEUE 101

ENQUEUE 201

ENQUEUE 102

ENQUEUE 202

ENQUEUE 103

ENQUEUE 203

DEQUEUE

DEQUEUE

DEQUEUE

DEQUEUE

DEQUEUE

DEQUEUE

STOP

【样例输出】

101

102

103

201

202

203


【样例说明】

    测试数据的文件名为in.txt

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;

// Press Shift twice to open the Search Everywhere dialog and type `show whitespaces`,
// then press Enter. You can now see whitespace characters in your code.
public class Main {
    public static void main(String[] args) {
        String filePath="in.txt";
        String line;
        int count;
        Map<Integer, Integer> map=new HashMap<>();                              //队员编号对应团队编号
        Map<Integer, Queue<Integer>> queueMap=new HashMap<>();                  //团队编号对应团队队列
        Queue<Queue<Integer>> queue=new LinkedList<>();                         //总队列包含团队队列

        try(BufferedReader br=new BufferedReader(new FileReader(filePath))){
            count=Integer.parseInt(br.readLine());
            for(int i=1;i<=count;i++){                                          //初始化队员对应团队的map
                line=br.readLine();
                String[] data=line.split(" ");
                for (int j=1;j<data.length;j++){
                    map.put(Integer.parseInt(data[j]),i);
                }
            }

            while((line= br.readLine())!=null){                                 //执行操作
                String[] data=line.split(" ");
                switch (data[0]){
                    case "ENQUEUE":
                        int id=Integer.parseInt(data[1]);
                        int teamID=map.get(id);
                        if(queueMap.containsKey(teamID)){                       //若是所在团队已经存在队列,则添加
                            queueMap.get(teamID).add(id);
                        }
                        else {                                                  //否则创建新队列,加入总队列和map中
                            Queue<Integer> q=new LinkedList<>();
                            queueMap.put(teamID,q);
                            queue.add(q);
                            q.add(id);
                        }
                        break;
                    case "DEQUEUE":                                             //总队列的第一个队列出队
                        if(queue.peek().size()==1){                             //如果出队是团队队列最后一个,从队列map中删除
                            queueMap.remove(map.get(queue.peek().peek()));
                            System.out.println(queue.peek().poll());
                            queue.poll();
                        }else {
                            System.out.println(queue.peek().poll());
                        }
                        break;
                    case "STOP":
                        break;
                }
            }
        }catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

 5-2.扔钉子

【问题描述】

年度学校自行车比赛开始了,ZL是这所学校的学生,他太无聊了,因为他不能骑自行车!因此,他决定干预比赛,他通过以前的比赛视频获得了选手的信息,一个选手第一秒可以跑F米,然后每秒跑S米。每个选手有一条直线跑道,ZL每秒向跑的最远的运动员跑道扔一个钉子,在自行车胎爆炸之后,该选手将被淘汰。如果有多个选手是NO.1,则他总是选择ID最小的选手扔钉子。

【输入形式】

每个测试用例的第一行包含一个整数n(1≤n≤50000),表示选手人数,然后跟随n行,每行包含第i个选手的两个整数Fi(0≤Fi≤500),Si(0<Si≤100),表示该选手第一秒可以跑Fi米,然后每秒跑Si米,i是玩家从1开始的ID。

【输出形式】

    输出n个数字,以空格分隔,第i个数字是选手的ID,该选手将在第i秒结束时被淘汰。

【样例输入】

 3

100 1

100 2

3 100

【样例输出】

1 3 2

【样例说明】

测试数据的文件名为in.txt

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class Main2 {
    public static void main(String[] args){
        String filePath="in.txt";
        String line;
        int count;                                              //选手个数
        int[] beginSpeed;                                       //初速度数组
        int[] speed;                                            //速度数组
        int[] exitOrder;                                        //退场顺序数组

        try(BufferedReader br=new BufferedReader(new FileReader(filePath))){
            line= br.readLine();
            count=Integer.parseInt(line);                       //获取选手个数,确定数组大小
            beginSpeed=new int[count];
            speed=new int[count];
            exitOrder=new int[count];

            for (int i=0;i<count;i++){                          //阅读文件,为初速度和速度数组赋值
                line= br.readLine();
                String[] data=line.split(" ");
                beginSpeed[i]=Integer.parseInt(data[0]);
                speed[i]=Integer.parseInt(data[1]);
            }

        }catch (IOException e){
            throw new RuntimeException(e);
        }

        for (int i=1;i<=count;i++){                             //i为度过的秒数
            int max=0;
            int ID=0;
            for (int j=0;j<count;j++){                          //找出距离最大值以及对应的选手ID
                int distance=beginSpeed[j]+speed[j]*(i-1);
                if(distance>max){
                    max=distance;
                    ID=j;
                }
            }
            beginSpeed[ID]=0;                                   //对应ID选手退场,速度归零
            speed[ID]=0;
            exitOrder[i-1]=ID+1;                                //当前秒数退场选手ID存入数组
        }
        for(int i=0;i<count;i++){
            System.out.print(exitOrder[i]+" ");                 //遍历输出
        }
    }
}

实验作业

实验作业只允许提交c++代码,又用回了c++

Ep1.产生n阶螺旋数字矩阵

编写一个程序,对任意输入的正整数n(n不大于10),产生并显示n阶螺旋式数字方阵。如n=3 要显示的方阵为

1 2 3
8 9 4
7 6 5

【输入形式】

输入一个数n
【输出形式】

产生n阶螺旋数字矩阵,数字以空格隔开
【样例输入】

3

【样例输出】 

1 2 3
8 9 4
7 6 5

【样例说明】

注意输出的数字以空格隔开

 

#include<iostream>
using namespace std;
enum direction{                        //枚举运动方向
  RIGHT,
  DOWN,
  LEFT,
  UP,
};

int main(){
  int n;
  cin>>n;
  int matrix[n][n];                    //定义二维数组
  int i=0,j=0;                         //i,j表示当前位置
  int top=0,left=0;
  int bottom=n-1,right=n-1;            //初始化上下左右的边界
  direction d=RIGHT;                   //初始运动方向向右
  for(int num=1;num<=n*n;num++){       //数组数值范围1-n*n
    matrix[i][j]=num;                  //当前位置数值为num
    switch (d)
    {
      case UP:                         //方向为上时,如果到达顶部边界,方向变为右
      if (i==top)                      //左边边界向里移动,其他方向同理
        {
          d=RIGHT;
          left++;
          j++;
        }                              
        else i--;                      //否则位置向上移动
        break;
      case LEFT:
        if (j==left)
        {
          d=UP;
          bottom--;
          i--;
        }
        else j--;
        break;
      case RIGHT:
        if (j==right)
        {
          d=DOWN;
          top++;
          i++;
        }
        else j++;
        break;
      case DOWN:
        if (i==bottom)
        {
          d=LEFT;
          right--;
          j--;
        }
        else i++;
        break;
    }
  }
  
  for (int i = 0; i < n; i++)                //遍历输出二维数组
  {
    for (int j = 0; j < n; j++)
    {
      cout<<matrix[i][j]<<" ";
    }
    cout<<endl;
  }
  
}

Ep2.计算器(表达式计算-后缀表达式实现)

【问题描述】

从标准输入中读入一个整数算术运算表达式,如24 / ( 1 + 2 + 36 / 6 / 2 - 2) * ( 12 / 2 / 2 )= ,计算表达式结果,并输出。

要求:

1、表达式运算符只有+、-、*、/,表达式末尾的=字符表示表达式输入结束,表达式中可能会出现空格;
2、表达式中会出现圆括号,括号可能嵌套,不会出现错误的表达式;

3、出现除号/时,以整数相除进行运算,结果仍为整数,例如:5/3结果应为1。

4、要求采用逆波兰表达式来实现表达式计算。

【输入形式】

从键盘输入一个以=结尾的整数算术运算表达式。操作符和操作数之间可以有空格分隔。

【输出形式】

在屏幕上输出计算结果(为整数,即在计算过程中除法为整除)。

【样例输入】

24 / ( 1 + 2 + 36 / 6 / 2 - 2) * ( 12 / 2 / 2 )     =

【样例输出】

18

【样例说明】

按照运算符及括号优先级依次计算表达式的值。

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

string midToBack(string exp){
	string num;
	string backexp;
	stack<char> signStack;
	for (int i = 0; i < exp.size(); i++) {				//遍历表达式
		if (exp[i] >= '0' && exp[i] <= '9') {
			num += exp[i];														//用num读取多位数字
		} else {
			backexp += num;														//读取到字符时数字添加到后缀表达式
			if(num!=""){
				backexp += " ";
			}
      num="";
			switch (exp[i]) {
				case '+':
				case '-':																//读到加号和减号,除了左括号,之前所有符号添加到后缀表达式
					while (!signStack.empty()) {
						if (signStack.top() == '(') {
							break;
						}
						backexp.push_back(signStack.top());
						signStack.pop();
					}
					signStack.push(exp[i]);
					break;
				case '*':
				case '/':
					while (!signStack.empty()) {
						if (signStack.top() == '(' || signStack.top() == '+' || signStack.top() == '-') {		//读到乘除号,除了加减号和左括号,均添加到后缀表达式
							break;
						}
						backexp.push_back(signStack.top());
						signStack.pop();
					}
					signStack.push(exp[i]);
					break;
				case '(':																//左括号直接入栈
					signStack.push(exp[i]);
					break;
				case ')':																//读到右括号,所有符号均添加至表达式,直到读到左括号
					while (true) {
						if (signStack.top() == '(') {
							signStack.pop();
							break;
						}
						backexp.push_back(signStack.top());
						signStack.pop();
					}
					break;
			}
		}
	}

  backexp += num;																//添加最后一个数字并清空栈
	backexp += " ";
  while (!signStack.empty()) {
		backexp.push_back(signStack.top());
		signStack.pop();
	}

	return backexp;
}

int calculate(string exp){
	string num;
	stack<int> numStack;
	int a,b;
	for (int i = 0; i < exp.size(); i++) {				//遍历后缀表达式,计算
		if (exp[i] >= '0' && exp[i] <= '9') {
			num += exp[i];														//用num读取多位数字
		} else {
			if(num!=""){
				numStack.push(stoi(num));	
			}
      num="";
			switch (exp[i]) {
				case '+':
					a=numStack.top();
					numStack.pop();
					b=numStack.top();
					numStack.pop();
					numStack.push(b+a);
					break;
				case '-':																																				
					a=numStack.top();
					numStack.pop();
					b=numStack.top();
					numStack.pop();
					numStack.push(b-a);
					break;
				case '*':
				a=numStack.top();
					numStack.pop();
					b=numStack.top();
					numStack.pop();
					numStack.push(b*a);
					break;
				case '/':
					a=numStack.top();
					numStack.pop();
					b=numStack.top();
					numStack.pop();
					numStack.push(b/a);
					break;
			}
		}
	}
	return numStack.top();
}

int main() {
	string exp;
	getline(cin,exp);
	string backexp=midToBack(exp);
	int ans=calculate(backexp);
	cout<<ans;
}

Ep3.二维表等值联接运算

 【问题描述】

R是m1×n1的二维表(整数矩阵)和S是m2×n2的二维表(整数矩阵),做等值联接运算,结果C=每一组测试数据的第一行为2个正整数m1,n1(0<m1,n1≤10),表示给定的矩形有m1行n1列。接下来这个矩阵,有m1行,每行有n1个不大于1000的正整数。接着一行是2个正整数m2,n2(0<m2,n2≤10),接下来这个矩阵,有m2行,每行有n2个不大于1000的正整数。然后输入第一个表R的列序号a1和第二个表S的列序号a2。

【输出形式】

  输出等值联接运算结果表

【样例输入】

 3 3

 1 2 3

 2 3 6

 4 5 8

 3 4

 3 6 9 12

 5 7 8 6

 9 6 5 8

 3 2

【样例输出】以文件abc.out输出

2 3 6 3 6 9 12

2 3 6 9 6 5 8  

【样例说明】

测试数据的文件名为in.txt

【评分标准】

要使用链表实现,否则不能得分。

#include<iostream>
#include<fstream>
#include<sstream>
#include<string>
#include<cassert>
#include<vector>
using namespace std;
struct DataNode //定义数据结点类型
{
    vector<int> data; // 节省空间
    DataNode *next;        //指向后继数据结点
};

struct HNode //定义头结点类型
{
    int Row, Col;   //行数和列数
    DataNode *next; //指向第一个数据结

    HNode() : next(NULL) {} // 构造函数
    HNode(int r, int c)     // 重载构造函数
    {
        Row = r;
        Col = c;
        next = NULL;
    }
};
HNode* build(ifstream &in){
  int r,c,d;
  in>>r>>c;                           //输入行和列
  in>>ws;
  string line;

  HNode *head=new HNode(r,c);
  DataNode *curNode=new DataNode();
  for(int i=0;i<r;i++){                 //构造链表
    getline(in,line);
    stringstream stream(line);
    DataNode *data=new DataNode();
    while (stream >>d)
    {
      data->data.push_back(d);
    }
    if(i==0){
      head->next=data;
    }
    else{
      curNode->next=data;
    }
    curNode=data;
  }
  return head;
}
void connect(HNode *headA,HNode *headB,int a,int b){
  ofstream out("abc.out");
  DataNode* dataA=headA->next;
  DataNode* dataB=headB->next;
  while (dataA!=nullptr)                        //遍历AB判断条件并输出
  {
    while (dataB!=nullptr)
    {
      if(dataA->data[a-1]==dataB->data[b-1]){
        for (auto it:dataA->data)
        {
          out<<it<<" ";
        }
        for (auto it:dataB->data)
        {
          out<<it<<" ";
        }
        out<<endl;
      }
      dataB=dataB->next;
    }
    dataB=headB->next;
    dataA=dataA->next;
  }
  
}
int main(){
  ifstream input("in.txt");
  assert(input.is_open());
  HNode *headA=build(input);
  HNode *headB=build(input);
  int a=0,b=0;
  input>>a>>b;
  connect(headA,headB,a,b);
  
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值