BUAA 数据结构总结——第4节(栈和队)

<< 其他专栏文章

栈操作

类型定义

#define MAXSIZE 1000
ElemType STACK[MAXSIZE];
int Top=-1; //初始化堆栈

进栈

void push(char s[], char item)//入栈
{
    if(Top == MAXSIZE-1)//isFull() 栈满
        return EOF;
    else
        s[++Top]=item;
}

出栈

char pop(char s[])//出栈
{
      if(Top == -1)//isEmpty() 空栈
          return EOF;
      else
          return s[Top--];
}

第四次作业

4.1 栈操作(栈-基本题)

【问题描述】

假设给定的整数栈初始状态为空,栈的最大容量为100。从标准输入中输入一组栈操作,按操作顺序输出出栈元素序列。栈操作:1表示入栈操作,后跟一个整数(不为1、0和-1)为入栈元素;0表示出栈操作;-1表示操作结束。

【输入形式】

从标准输入读取一组栈操作,入栈的整数和表示栈操作的整数之间都以一个空格分隔。

【输出形式】

在一行上按照操作的顺序输出出栈元素序列,以一个空格分隔各元素,最后一个元素后也要有一个空格。如果栈状态为空时进行出栈操作,或栈满时进行入栈操作,则输出字符串“error”,并且字符串后也要有一空格。所有操作都执行完后,栈也有可能不为空。

【样例输入】

1 3 1 5 1 7 0 0 1 8 0 1 12 1 13 0 0 0 0 1 90 1 89 0 -1

【样例输出】

7 5 8 13 12 3 error 89

【样例说明】

入栈元素依次为3、5、7,然后有两次出栈动作,所以先输出7和5,这时栈中只有元素3;之后元素8入栈,又出栈,输出8;随后元素12和13入栈,再进行4次出栈操作,输出13、12和3,这时栈为空,再进行出栈操作会输出error;最后90和89入栈,进行一次出栈操作,输出89,栈中剩余1个元素。

「代码」
#include <stdio.h>
#define MAXSIZE 100
int STACK[MAXSIZE];
int Top = -1;                  //initStack() 初始化栈
void push(int s[], int item);  //入栈
void pop(int s[]);             //出栈

int main(int argc, const char * argv[]) {
    while (1)
    {
        int sign;
        scanf("%d",&sign);
        
        if(sign==1)//入栈操作
        {
            int in;//入栈元素
            scanf("%d",&in);//后跟一个整数(不为1、0和-1)为入栈元素;
            push(STACK, in);
        }
        else if(sign==0)//出栈操作
        {
            pop(STACK);
        }
        else if(sign==-1) break;//操作结束。
    }
    return 0;
}

void push(int s[], int item)
{
    if(Top == MAXSIZE-1)//isFull() 栈满
        printf("error ");
    else
        s[++Top]=item;
}

void pop(int s[])
{
      if(Top == -1)//isEmpty() 空栈
          printf("error ");
      else
          printf("%d ", s[Top--]);
}

4.2 C程序括号匹配检查

【问题描述】

编写一程序检查C源程序文件中{}、()等括号是否匹配,并输出第一个检测到的不匹配的括号及所对应括号所在的行号(程序中只有一个括号不匹配)。

注意:

  1. 除了括号可能不匹配外,输入的C源程序无其它语法错误。

  2. 字符常量、字符串常量及注释中括号不应被处理,注释包括单行注释//和多行/* */注释

  3. 字符常量和字符串常量中不包含转义字符’和";

  4. 程序中出现有意义括号的个数不超过200个;

不匹配判断规则:

  1. 当检测的程序括号为’{‘时,若其前序尚未匹配的括号为’(‘时,输出该’('左括号及所在行号;

  2. 当遇到一个不匹配的右括号’)‘或’}'时,输出该右括号及所在行号;

  3. 当程序处理完毕时,还存在不匹配的左括号时,输出该左括号及所在行号。

【输入形式】

打开当前目录下文件example.c,查询其括号是否匹配。该文件中每行字符数不超过200。

【输出形式】

若存在括号不匹配时,应输出首先能判断出现不匹配的括号及其所在的行号。当出现括号不匹配时,按下面要求输出相关信息:

without maching at line

其中为‘{’, ‘}’, ‘(’, ‘)’等符号,为该符号所在的行号。

若整个程序括号匹配,则按下面所示顺序输出括号匹配情况,中间没有空格。

(){(()){}}

【样例输入1】

若当前目录下输入文件example.c中内容如下:

#include<stdio.h>
int main(){
printf("{ hello world }\n"); // }
)

【样例输出1】

without maching ‘)’ at line 4

【样例输入2】

若当前目录下输入文件example.c中内容如下:

#include<stdio.h>
int main(){
printf("{ hello world }d\n"); /* }*/

【样例输出2】

without maching ‘{’ at line 2

【样例输入3】

若当前目录下输入文件example.c中内容如下:

#include<stdio.h>
int main(){
printf("{ hello world }d\n"); /* }*/
}

【样例输出3】

(){()}

【样例说明】

样例1:在注释部分和字符串中的括号不考虑,在将程序处理之后得到的括号序列是(){()),遇到右括号时与最近的左括号匹配,发现最后一个小括号和大括号不匹配。

样例2:处理之后的括号序列是(){(),在最后缺少了右大括号,那么应该输出与之相对应的左括号不匹配。

「代码」

//字符常量''、字符串常量""及注释(包括单行注释//和多行/* */注释)中,括号不应被处理(V2.0)
/*
 不匹配判断规则:
 1.当检测的程序括号为'{'时,若其前序尚未匹配的括号为'('时,输出该'('左括号及所在行号;
 2.当遇到一个不匹配的右括号')'或'}'时,输出该右括号及所在行号;
 3.当程序处理完毕时,还存在不匹配的左括号时,输出该左括号及所在行号。
 */

#include <stdio.h>
#define MAXSIZE 200 //程序中出现有意义括号的个数不超过200个

char STACK[MAXSIZE]; //STACK栈;
char brackets[MAXSIZE]; //brackets存储所有括号,用于整个程序括号匹配时输出括号匹配情况
int bracket_line[MAXSIZE]; //line存储括号的行号
int line=1; //记录当前行号
int Top = -1;                  //initStack() 初始化栈
void push(char s[], char item);  //入栈
char pop(char s[]);             //出栈

int main(int argc, const char * argv[]) {

    FILE *fi;
    if((fi = fopen("example.c", "r")) == NULL)
    {
        printf("Can't open file example.c !\n");
        return 404;
    }

    char c;//读入的字符
    int i=0;//brackets的索引
    while ((c=fgetc(fi))!=EOF)
    {
        //字符常量''、字符串常量""及注释(包括单行注释//和多行/* */注释)中,括号不应被处理(V2.0)
        if(c=='\'')
        {
            while (c=fgetc(fi),c!='\'')
                ;
            continue;
        }
        else if(c=='\"')
        {
            while (c=fgetc(fi),c!='\"')
                ;
            continue;
        }
        else if(c=='/')
        {
            if(c=fgetc(fi),c=='/')
            {
                while (c=fgetc(fi),c!='\n')
                    ;
                line++;/*⚠️*/
                continue;
            }
            else if(c=='*')
            {
                while ((c=fgetc(fi),c!='*')&&(c=fgetc(fi),c!='/'))
                    if(c=='\n')line++;;
                continue;
            }
        }
        
        if ( c=='(' || c=='{' )
        {

            if ( c=='{' && STACK[Top-1]=='(' )
            {
                //其前序尚未匹配的括号为'('时,输出该'('左括号及所在行号
                printf("without maching '%c' at line %d\n",STACK[Top-1],bracket_line[Top-1]);
                return 0;
            }

            push(STACK, c);

            bracket_line[Top]=line;//与栈对应
            brackets[i++]=c;
        }
        else if ( c==')' || c=='}' )
        {
            char out; //出栈元素,为左括号
            out=pop(STACK);
            if (( out=='(' && c==')' )||( out=='{' && c=='}' ))
            {
                //与当前的右括号组成一对,匹配成功
                brackets[i++]=c;
            }
            else
            {
                //不匹配的右括号')'或'}'时,输出该右括号及所在行号
                printf("without maching '%c' at line %d\n",c,line);
                return 0;
            }
        }
        if ( c=='\n' )//if 避免注释判断失效导致line未++
        {
            line++;
        }
    }

    if(Top!=-1)
    {
        //当程序处理完毕时,还存在不匹配的左括号时(即栈非空),输出该左括号及所在行号。
        printf("without maching '%c' at line %d\n",STACK[Top],bracket_line[Top]);
        return 0;
    }

    puts(brackets);//整个程序括号匹配,输出括号匹配情况

    return 0;
}

void push(char s[], char item)//入栈
{
    if(Top == MAXSIZE-1)//isFull() 栈满
        printf("error ");
    else
        s[++Top]=item;
}

char pop(char s[])//出栈
{
      if(Top == -1)//isEmpty() 空栈
          return EOF;
      else
          return s[Top--];
}

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

【问题描述】

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

要求:

  1. 表达式运算符只有+、-、*、/、%,表达式末尾的=字符表示表达式输入结束,表达式中可能会出现空格;

  2. 表达式中会出现圆括号,括号可能嵌套,不会出现错误的表达式;

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

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

【输入形式】

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

【输出形式】

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

【样例输入】

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

【样例输出】

18

【样例说明】

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

「代码」
//  后缀表达式

/*----- ppt代码,需要完善void operate(enum oper op );函数 -----*/
/*
 算法:
 对于问题3.1我们没有必要象编译程序那样先将中缀表达式转换为后缀表达式,然后再进行计算。
 为此,可设两个栈,一个为数据栈,另一个为运算符栈,在转换中缀表达式的同时进行表达式的计算。主要思路为:当一个运算符出栈时,即与数据栈中的数据进行相应计算,计算结果仍存至数据栈中。算法如下:
 1.从输入(中缀表达式)中获取一项:
 若是数字则压入数据栈中;
 若是符号:
 若是),则将符号栈中元素弹出并与数据栈中元素进行计算、计算结果放回数据栈中,直到遇到“(”, “(”弹出但不计算;
 若是(,+,*等符号,则从符号栈中弹出优先级高于当前的符号并与数据栈中元素进行计算、计算结果放回数据栈中,直到遇到一个优先级低的符号;然后将当前符号压入栈中。
 若是=号,将符号栈中所有元素依次弹出并与数据栈中元素进行计算、计算结果放回数据栈中,直到符号栈为空,此时数据栈中为计算结果;否则转1。
 */

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<ctype.h>
#define  MAXSIZE 100
typedef  int  DataType;
enum  symbol {NUM, OP, EQ,OTHER};//符号类型
enum  oper {EPT, LEFT, RIGHT, ADD, MIN, MUL, DIV, MOD}; //运算类型及优先级
int Pri[]={  -1,   0,    0,    1,   1,   2,   2,   2 }; //运算符优先级
union sym {
    DataType num;
    enum oper op;
} ; //符号值

enum symbol getSym( union sym *item);
void operate(enum oper op );//操作运算符
void compute(enum oper op ); //进行运算

void pushNum(DataType num);
DataType popNum(void);

void pushOp(enum oper op);
enum oper  popOp(void);
enum oper  topOp(void);

void error(char s[ ]);

DataType Num_stack[MAXSIZE]; //数据栈
int Ntop=-1; //数据栈顶指示器,初始为空栈

enum oper Op_stack[MAXSIZE];//符号栈
int  Otop=-1; //运算符栈顶指示器,初始为空栈

int main()
{
    union sym item;
    enum symbol s;
    while( (s = getSym(&item))  != EQ) {
        if(s == NUM)
            pushNum(item.num);
        else if(s == OP)
            operate(item.op);
        else {
            printf("Error in the expression1!\n");
            return 1;
        }
    }
    while(Otop >=0) //将栈中所有运算符弹出计算
        compute(popOp());
    if(Ntop == 0) //输出计算结果
        printf("%d\n", popNum());
    else
        printf("Error in the expression2!\n");
    return 0;
}

enum symbol getSym( union sym *item)
{
    int  c, n;
    while((c = getchar()) != '=') {
        if(c >= '0' && c <= '9'){
            for(n=0; c >= '0' && c <= '9'; c= getchar())
            n = n*10 + c-'0';
            ungetc(c, stdin);
            item->num = n;
            return NUM;
        }
        else
            switch(c)  {
                case '+': item->op = ADD; return OP;
                case '-': item->op = MIN; return OP;
                case '*': item->op = MUL; return OP;
                case '/': item->op = DIV; return OP;
                case '%': item->op = MOD; return OP;
                case '(': item->op = LEFT; return OP;
                case ')': item->op = RIGHT; return OP;
                case ' ': case '\t': case '\n': break;
                default: return OTHER;
            }
    }
    return EQ;
}

void operate(enum oper op )
{
    /*
     若是),
     则将符号栈中元素弹出并与数据栈中元素进行计算、计算结果放回数据栈中,直到遇到“(”, “(”弹出但不计算;
     若是(,+,*等符号,
     则从符号栈中弹出优先级『高于等于』(由于乘除仅仅取整,导致运算精度低 ,乘除改变顺序会导致结果产生误差)
     当前的符号并与数据栈中元素进行计算、计算结果放回数据栈中,直到遇到一个优先级低的符号;
     然后将当前符号压入栈中。
     */
    
    if (op == RIGHT) {   //运算符为右括号时,开始弹栈,直到弹出左括号
        enum  oper c;
        while ( (c=popOp()) != LEFT)
            compute(c);
    }
    else if (Otop ==-1 || op == LEFT ) {   //空栈或者栈顶为左括号时直接将运算符压栈
        pushOp(op);
    }
    else //if(op==MUL || op==DIV || op== MOD || op==ADD || op==MIN)
    {
        while(Otop >=0 && Pri[topOp()]>=Pri[op] )
            compute(popOp());
        pushOp(op);
    }
}

void compute(enum oper op )
{
    DataType  tmp;
    switch(op) {
            
        case ADD:
            pushNum(popNum() + popNum()); break;
        case MIN:
            tmp = popNum();
            pushNum(popNum() - tmp); break;
        case  MUL:
            pushNum(popNum() * popNum()); break;
        case DIV:
            tmp = popNum();
            pushNum(popNum() / tmp); break;
        case MOD:
            tmp = popNum();
            pushNum(popNum() % tmp); break;
        case LEFT:case EPT:case RIGHT: break;
    }
}

//数据栈操作

void pushNum(DataType num)
{
    if(Ntop == MAXSIZE -1)
        error("Data stack is full!");
    Num_stack[++Ntop] = num;
}
DataType popNum()
{
    if(Ntop == -1)
        error("Error in the expression!3");
    return Num_stack[Ntop--] ;
}
void error(char s[ ])
{
    fprintf(stderr, "%s\n",s);
    exit(1);
}

//运算符栈操作

void pushOp(enum oper op)
{
    if(Ntop == MAXSIZE -1)
        error("Operator stack is full!");
    Op_stack[++Otop] = op;
}
enum oper  popOp()
{
    if(Otop != -1){
        return Op_stack[Otop--] ;
    }
    return EPT;
}
enum oper  topOp()
{
    return Op_stack[Otop];
}

4.4 文本编辑操作模拟(简)a

【问题描述】

编写一程序模拟文本编辑操作。首先从标准输入读取一行字符串(字符个数不超过512),该行字符串是已经过n(大于0,小于等于10)步编辑操作后的结果。然后从下一行读取n,以及已发生过的n步编辑操作,编辑操作分行输入,输入格式为:

op pos str

其中op为编辑操作命令编码(在此只有插入和删除操作,1表示插入或2表示删除操作);pos表示插入或删除的位置;str表示已经插入或删除的字符串(中间没有空格)。各数据间以一个空格分隔。

然后在空一行后,再分行输入当前将要进行的编辑操作,包括如下四种操作(操作编码分别为:1表示插入,2表示删除操作,3表示撤销(即undo操作),-1表示结束):

1 pos str

表示将在pos位置插入字符串str(中间没有空格),各数据间以一个空格分隔;

2 pos n

表示将从pos位置开始删除n个字符(各数据间以一个空格分隔),若要删除的字符个数多于已有字符个数(即在文本中从pos开始的字符个数小于n),则按实际字符数删除即可。(提示:为了能够撤销删除操作,应按“2 pos str”形式保存命令。)

3

表示撤销最近执行的插入或删除操作,可以进行多次撤销操作,注意:也可以撤销之前已经发生过的n步编辑操作中的操作。

-1

表示退出编辑操作,在屏幕上输出最终编辑后的文本。

要求:

1、上述所有输入的编辑操作中的字符串str都不包含空白字符(空格符、制表符或换行符);

2、插入操作中的位置pos大于等于0,并且小于等于当前文本的字符个数;0位置表示文本第一个字符的位置;若pos为当前文本的字符个数,则表示在文本最后插入字符串;

3、删除操作中的位置pos大于等于0,并且小于当前文字的字符个数;

4、若已无操作可撤销,则再进行撤销操作无效;

5、文本在编辑过程中,总字符个数不会超过512。

【输入形式】

先从键盘输入一行字符串,表示已经经过n步编辑操作后的文本串,然后在下一行输入一个正整数n,并分行输入n步插入或删除操作(表示按时间先后顺序已进行的操作),格式如上所述。随后空一行,再分行输入将要进行的编辑操作,格式如上所述。直到输入-1操作为止。

【输出形式】

在屏幕上输出最终编辑后的文本内容。

【样例输入】

A Stack is a container of objects that are inserted and removed according to the last-in first-out (LIFO) principle.???

4
1 20 ainer
2 0 ???
1 85 -
1 99 (LIFO)

3
2 110 10
1 110 Objects
2 98 1
2 0 1
2 108 10
3
3
3
-1

【样例输出】

A Stack is a container of objects that are inserted and removed according to the last-in first-out principle.Objects

【样例说明】

第一行输入的文本串是先后经过下面4次编辑操作后得到的:先在20位置插入了字符串ainer,然后删除了开始位置的字符串???,随后在85位置插入了一个字符-,最后在99位置插入了字符串(LIFO)。

随后输入了撤销操作,即撤销先前最后进行的“1 99 (LIFO)”操作,也就是将99位置的6个字符删除;

2 110 10:将文本串最后的字符串???删除;

1 110 Objects:在文本串末尾插入字符串Objects;

随后执行了三次删除操作,又执行了三次撤销操作,最后输入的-1表示编辑操作结束,在屏幕上输出最终编辑后的文本串。

「代码」
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define MAXSIZE 520//512
struct STACK {
    int op;
    int pos;
    char str[MAXSIZE];
    char S[MAXSIZE];//当前步骤操作后的字符串
    //op pos str
    //op 编辑操作命令编码(1-插入 或2-删除);
    //pos 插入或删除的位置;
    //str 已经插入或删除的字符串.
};

struct STACK stack[200];//结构体栈
int Top = 0;//0预留出进行最后一次撤销

void insert(int pos, char str[]);
void delete(int pos, int n);

void re_insert(int pos, int n);
void re_delete(int pos, char str[]);

int main(int argc, const char * argv[]) {
    
    char s[MAXSIZE];
    gets(s);//首先读取一行字符串
    
    int N;
    scanf("%d",&N);//已经过n步编辑操作
    
    for(int i=1;i<=N;i++)
    {
        //已发生过的n步编辑操作 op pos str
        Top++;
        scanf("%d %d %s",&stack[Top].op,&stack[Top].pos,stack[Top].str);
    }
    
    strcpy(stack[Top].S,s);
    
    while(1)
    {
        int op;
        scanf("%d",&op);
        
        
        if(op==1) //1-插入
        {
            //1 pos str
            int pos; char str[MAXSIZE];
            scanf("%d %s",&pos,str);
            Top++;
            insert(pos, str);
            ;
        }
        
        else if(op==2) //2-删除
        {
            //2 pos n
            int pos,n;
            scanf("%d %d",&pos,&n);
            Top++;
            delete(pos, n);
        }
        
        else if(op==3) //3-撤销
        {
            if(Top==0)
                continue;
            else if(Top>N)
                Top--;
            else{
                //撤销之前已经发生过的n步编辑操作
                if(stack[Top].op==1)
                {
                    Top--;
                    re_insert(stack[Top+1].pos, strlen(stack[Top+1].str));
                    //注意此处S保存在Top位置 但需要撤回的操作在Top+1位置
                }
                else if (stack[Top].op==2)
                {
                    Top--;
                    re_delete(stack[Top+1].pos, stack[Top+1].str);
                }
            }
        }
        
        else if(op==-1){ //-1-结束
            puts(stack[Top].S);
            return 0;
            
        }
    }
}

void insert(int pos, char str[]) {//在pos位置插入字符串str
    strcpy(stack[Top].S, stack[Top-1].S);
    strcpy(stack[Top].S + pos, str);
    strcpy(stack[Top].S + pos + strlen(str), stack[Top-1].S + pos);
}

void delete(int pos, int n){//从pos位置开始删除n个字符
    int len = strlen(stack[Top-1].S);
    
    if (len-pos<n)//若删除的字符个数多于已有字符个数(即从pos开始的字符个数小于n)
        n = len - pos;//则按实际字符数删除
    
    strcpy(stack[Top].S, stack[Top-1].S);
    strcpy(stack[Top].S + pos, stack[Top-1].S + pos + n);
    stack[Top].S[len - n] = '\0';
}

void re_insert(int pos, int n) { //即在pos位置删除n个字符(字符串str的长度)
    int len = strlen(stack[Top+1].S);
    strcpy(stack[Top].S, stack[Top+1].S);
    strcpy(stack[Top].S + pos, stack[Top+1].S + pos + n);
    stack[Top].S[len - n] = '\0';
}

void re_delete(int pos, char str[]){//即从pos位置开始插入字符串str
    strcpy(stack[Top].S, stack[Top+1].S);
    strcpy(stack[Top].S + pos, str);
    strcpy(stack[Top].S + pos + strlen(str), stack[Top+1].S + pos);
}

4.5 银行排队模拟(生产者-消费者模拟)

【问题描述】

一个系统模仿另一个系统行为的技术称为模拟,如飞行模拟器。模拟可以用来进行方案论证、人员培训和改进服务。计算机技术常用于模拟系统中。

生产者-消费者(Server-Custom)是常见的应用模式,见于银行、食堂、打印机、医院、超等提供服务和使用服务的应用中。这类应用的主要问题是消费者如果等待(排队)时间过长,会引发用户抱怨,影响服务质量;如果提供服务者(服务窗口)过多,将提高运管商成本。(经济学中排队论)

假设某银行网点有五个服务窗口,分别为三个对私、一个对公和一个外币窗口。银行服务的原则是先来先服务。通常对私业务人很多,其它窗口人则较少,可临时改为对私服务。假设当对私窗口等待服务的客户(按实际服务窗口)平均排队人数超过(大于或等于)7人时,等待客户将可能有抱怨,影响服务质量,此时银行可临时将其它窗口中一个或两个改为对私服务,当客户少于7人时,将立即恢复原有业务。设计一个程序用来模拟银行服务。

说明:

  1. 增加服务窗口将会增加成本或影响其它业务,因此,以成本增加或影响最小为原则来增加服务窗口,即如果增加一个窗口就能使得按窗口平均等待服务人数小于7人,则只增加一个窗口。一旦按窗口平均等待服务人数小于7人,就减少一个所增加的窗口。

  2. 为了简化问题,假设新到客户是在每个服务周期开始时到达。

  3. 当等待服务人数发生变化时(新客户到达或有客户已接受服务),则及时计算按实际服务窗口平均等待服务人数,并按相应策略调整服务窗口数(增加或减少额外的服务窗口,但对私窗口不能减少)。注意:只在获取新客户(不管到达新客户数是否为0)时或已有客户去接受服务时,才按策略调整服务窗口数。进一步讲,增加服务窗口只在有客户到达的周期内进行(也就是说增加窗口是基于客户的感受,银行对增加窗口是不情愿的,因为要增加成本,一旦不再有新客户来,银行是不会再增加服务窗口的);一旦有客户去接受服务(即等待客户减少),银行将根据策略及时减少服务窗口,因此,在每个周期内,有客户去接受服务后要马上判断是否减少服务窗口(因为能减少成本,银行是积极的)

本问题中假设对公和对外币服务窗口在改为对私服务时及服务期间没有相应因公或外币服务新客户到达(即正好空闲),同时要求以增加成本或影响最小为前提,来尽最大可能减少对私服务客户等待时间。

【输入形式】

首先输入一个整数表示时间周期数,然后再依次输入每个时间周期中因私业务的客户数。注:一个时间周期指的是银行处理一笔业务的平均处理时间,可以是一分钟、三分钟或其它。例如:

6

2 5 13 11 15 9

说明:表明在6个时间周期内,第1个周期来了2个(序号分别为1,2),第2个来了5人(序号分别为3,4,5,6,7),以此类推。

【输出形式】

每个客户等待服务的时间周期数。输出形式如下:

用户序号 : 等待周期数

说明:客户序号与等待周期数之间用符号:分隔,冒号(:)两边各有一个空格,等待周期数后直接为回车。

【样例输入】

4
2 5 13 11

【样例输出】

1 : 0
2 : 0
3 : 0
4 : 0
5 : 0
6 : 1
7 : 1
8 : 0
9 : 1
10 : 1
11 : 1
12 : 1
13 : 2
14 : 2
15 : 2
16 : 3
17 : 3
18 : 3
19 : 4
20 : 4
21 : 3
22 : 4
23 : 4
24 : 4
25 : 5
26 : 5
27 : 5
28 : 6
29 : 6
30 : 6
31 : 7

【样例说明】

样例输入表明有四个时间周期,第一个周期来了2人(序号1-2);第二个周期来了5人(序号3-7);第三个周期来了13人(序号8-20);第四个周期来了11人(序号21-31)。由于第一个时间周期内只来了2人,银行(有三个服务窗口)能及时提供服务,因此客户等待时间为0;第二个时间周期内来了5人,银行一个周期内一次只能服务3人,另有2个在下个周期内服务,因此等待时间为1,其它类推。

「代码」
//others

#include<stdio.h>
struct queue{
    int time[3000];
};
struct queue q;
int head=1,tail=1;
int n,m,op,i;
int min(int x,int y)
{
    return x>y?y:x;
}
void chooseOP1(int n)
{
    if(n<21)    op=3;    //开放窗口个数
    else if(n>=21 && n<28)        op=4;
    else op=5;
}
void chooseOP2(int n)
{
    if(n<28)    op=3;    //开放窗口个数
    else if(n>=28 && n<35)        op=4;
    else op=5;
}
int main()
{
    scanf("%d",&n);
    while(n--)
    {
        scanf("%d",&m);
        tail+=m;    //队尾增加
        chooseOP1(tail-head);
        for(i=head;i<min(head+op,tail);i++)
        {
            printf("%d : %d\n",i,q.time[i]);   //输出已经在窗口的客户
        }
        for(i=head+op;i<tail;i++)
        {
            q.time[i]++;              //等待的客户周期加1
        }
        head=min(head+op,tail);       //出队
        chooseOP1(tail-head);
    }
    while(head<tail)
    {
        chooseOP2(tail-head);
        for(i=head;i<min(head+op,tail);i++)
        {
            printf("%d : %d\n",i,q.time[i]);   //输出已经在窗口的客户
        }
        for(i=head+op;i<tail;i++)
        {
            q.time[i]++;              //等待的客户周期加1
        }
        head=min(head+op,tail);       //出队
        chooseOP2(tail-head);
    }
    return 0;
}

4.6 火车货运调度模拟(选做,不计分)

【问题描述】

某火车货场由A、B、C三段组成,见下图。现有一列货车停在A段上,由多个货物车厢组成,每节车厢信息包括编号和货物发往的目的地(车厢编号是唯一的,各节车厢发往的目的地可以相同,也可以不同)。当前停在A段的货车车厢发往目的地编组是乱的,需要按目的地由远至近进行重新编组,即车厢离车头越近其目的地越远,这样方便到达目的地时卸货(卸下相关车厢)。编组过程中车厢只能依次从A中移动至B或C中,或从B或C中移至A中,从B中不能直接移至C中,从C中也不能直接移至B中。编写一程序模拟货运车厢编组。
鐏溅璋冨害.png
假设A、B、C三段交叉路口为各段的顶端,编组规则如下:

  1. 初始时所有车厢位于A中且均未完成编组,车头距离顶端最远;首先将其所有车厢从顶开始依次推进至B中。

  2. 从B中找到发往地最远的车厢中离顶最近的车厢,假设其为M。将M至顶的所车厢依次推进至A中,此时M一定位于A中顶端。

  3. 若A中M之后(即:M与车头之间)不存在未完成编组的车厢,则车厢M的编组完成了;若A中M之后存在未完成编组的车厢,则将M推进至 C中,将A中M之后所有未完成编组的车厢依次推进至B中,再将M由C中推进至A中,这样就完成了车厢M的编组;

  4. 重复步骤2-3,直到B中无车厢。

【输入形式】

先从控制台输入目的地个数(大于等于1,小于等于50),然后分行输入一组由地名(用不含空白符的英文字符串表示,字符个数不超过20)和里程(用大于等于1小于等于10000的整数表示)构成的发往目的地(由近至远序)里程表,地名和里程之间以一个空格分隔;在里程表之后输入车厢个数(大于等于1,小于等于50),然后分行输入一组由车厢编号(由四位数字组成)和发往目的地(目的地肯定在上述里程表中出现)构成的车厢信息,车厢编号和目的地之间以一个空格分隔,并且是从车头处开始依次输入每节车厢信息。

【输出形式】

假设一节车厢从某段推出称为一次pop操作,推进某段称为一次push操作。程序运行输出第一行为从车头开始编好组的车厢编号,中间用一个空格隔开,最后一个车厢编号后也有一个空格。第二行输出编组过程中A段中push操作的次数。

【样例输入】

10
shijiazhuang 280
xingtai 390
xinxiang 610
zhengzhou 689
wuchang 1221
chibi 1339
yueyang 1434
changsha 1559
shaoguan 2057
guangzhou 2273

12
0039 guangzhou
5217 xingtai
0262 yueyang
7205 wuchang
3211 guangzhou
4893 shijiazhuang
2283 shaoguan
0890 guangzhou
8729 wuchang
6839 shijiazhuang
2122 changsha
3280 wuchang

【样例输出】

0039 3211 0890 2283 2122 0262 7205 8729 3280 5217 4893 6839
45

【样例说明】

首先输入由10个地名及其里程组成的里程表,然后输入了12节需要编组的车厢的编号和发往的目的地,即初始时处于A中的车厢,其中0039编号的车厢离车头最近。按照上面编组规则,首先将所有车厢推进至B中,这时0039车厢位于B的顶端,3280车厢位于底端,B中所有车厢中最远目的地为guangzhou、且离顶最近的车厢为0039,将其推进至A中,这时A中只有其一节车厢,其后没有未编组的车厢,0039车厢编组完成(即完成第一节车厢编组),此时A的push操作次数为1;接下来,B中剩余的11个车厢中,最远目的地依然为guangzhou,其离顶最近的车厢为3211,将该车厢及其上的3节车厢依次推进到A中,此时,3211车厢与火车头之间有三节车厢未完成编组,于是按规则将3211推进至C中,将7205、0262和5217依次推进至B中,再将C中的3211推进至A中,这时3211车厢编组完成(即完成第二节车厢编组),此时A的push操作次数为6;再依次按照上述步骤对B中剩余的车厢完成编组,直到B中无车厢。最后从车头开始将所有完成编组的车厢编号依次输出,由此得到一组发往目的地距离(从车头开始)由远至近的车厢序列。完成编组过程中A的push操作次数共有45次。

「代码」


  • 13
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
BUAA数据结构第四次编程题是关于栈操作的题目。题目要求使用数组模拟栈,并按照给定的操作顺序进行入栈和出栈操作。入栈操作表示将给定的数字压入栈中,出栈操作表示弹出栈顶元素并输出。如果栈状态为空时进行出栈操作,或栈已满时进行入栈操作,则输出"error"。最后,需要按照操作的顺序输出出栈元素序列,元素之间用空格分隔。如果栈最终不为空,则最后一个元素后也要有一个空格。 解题思路:使用一个数组来实现栈的数据结构,通过维护一个指针top来表示栈顶元素的位置。根据给定的操作进行相应的入栈和出栈操作。对于入栈操作,将给定的数字存入数组中,并将top指针加1。对于出栈操作,判断栈是否为空,若为空则输出"error",否则输出栈顶元素并将top指针减1。最后,按照操作的顺序输出出栈元素序列。 以下是参考代码: ``` #include<stdio.h> #include<string.h> #include<math.h> #include<stdlib.h> #include<ctype.h> struct stack{ int top; int data<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [BUAA(2021春)栈操作(栈-基本题)](https://blog.csdn.net/zhouEnshen/article/details/116305600)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值