zoukankan      html  css  js  c++  java
  • DS博客作业02--栈和队列

    这个作业属于哪个班级 数据结构--网络2011/2012
    这个作业的地址 DS博客作业02--栈和队列
    这个作业的目标 学习栈和队列的结构设计及运算操作
    姓名 王博

    0.PTA得分截图

    栈和队列题目集总得分,请截图,截图中必须有自己名字。题目至少完成2/3(不包括选择题),否则本次作业最高分5分。

    1.本周学习总结(0-5分)

    1.1 栈

    画一个栈的图形,介绍如下内容。

    • 顺序栈的结构、操作函数

      操作函数

      • 结构体

        struct SNode {
            ElementType* Data;  /* 存储元素的数组   */
            Position Top;     /* 栈顶指针 */
            int MaxSize;
        };
        
      • 入栈

      void PushStack(Stack S, ElementType x)
      {
          if (S->Top == S->MaxSize)
          {
              printf("Stack Full
      ");
              return;
          }
          S->Top++;
          S->Data[S->Top] = x;
      }
      
      • 出栈
      ElementType PopStack(Stack S)
      {
          if (S->Top == -1)
          {
              printf("Stack Empty
      ");
              return 0;
          }
          return S->Data[S->Top--];
      }
      
      • 栈空
      int StackEmpty(Stack S)
      {
          if (S->Top == -1)
              return 1;
          else
              return 0;
      }
      
    • 链栈的结构、操作函数

      操作函数

      • 结构体定义:
      typedef int Elmetype;
      struct SNode
      {
      	Elmetype data;
      	struct SNode* next;
      };
      typedef struct SNode* LinkStack;
      
      • 进栈:
      void Push(LinkStack& S, Elmetype X)
      {
      	LinkStack NewS = new SNode;
      	/*数据载入*/
      	NewS->data = X;
      	/*头插法插入新数据*/
      	NewS->next = S->next;
      	S->next = NewS;
      }
      
      • 出栈:
      bool Pop(LinkStack& S, Elmetype& e)
      {
      	/*首先要判断栈顶是否为空*/
      	if (S->next == NULL)
      	{
      		return false;
      	}
      	e = S->next->data;
      	LinkStack delSNode = S->next;
      	S->next = delSNode->next;
      	delete delSNode;
      	return true;
      }
      
      • 取栈顶元素:
      void DestoryLinkStack(LinkStack& S)
      {
      	LinkStack delS = S;
      	while (S != NULL)
      	{
      		S = S->next;
      		delete delS;
      		delS = S;
      	}
      }
      

    1.2 栈的应用

    • 表达式求值
    • 表达式转换
    • 符号的配对(创建一个栈,在读入字符的过程中,如果是左括号,则直接入栈,等待相匹配的同类右括号;如果是右括号,且与当前栈顶左括号匹配,则将栈顶左括号出栈)
    • 迷宫问题

    1.3 队列

    画一个队列的图形,介绍如下内容。

    队列是一种特殊的线性表,特殊之处在于它只允许在表的前端进行删除操作,而在表的后端进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头.

    • 顺序队列的结构、操作函数

      • 结构体定义
      typedef struct
      {
          ElemType data[MaxSize];
          int front, rear;
      }SqQueue;
      typedef SqQueue* Queue;
      
      • 初始化队列
      void InitQueue(Queue Q)
      {
          Q = (Queue)malloc(sizeof(SqQueue)*Max);
          Q->front = Q->rear = 0;
      }
      
      • 销毁队列
      void DestroyQueue(Queue Q)
      {
          free(Q);
      }
      
      • 判断队列是否为空
      bool QueueEmpty(Queue Q)
      {
          return (Q->front == Q->rear);
      }
      
      • 入队
      bool EnQueue(Queue Q,ElemType e)
      {
          if(Q->rear == MaxSize)
              return false;
          Q->data[Q->rear++] = e;
          return true;
      }
      
      • 出队
      bool DeQueue(Queue Q,ElemType &e)
      {
          if(Q->front == Q->rear)
              return false;
          e = Q->data[Q->front++];
          return true;
      }
      
    • 环形队列的结构、操作函数

      • 结构体定义
      typedef struct
      {
          ElemType data[MaxSize];
          int front, rear;
      }SqQueue;
      typedef SqQueue* Queue;
      
      • 初始化队列
      void InitQueue(Queue Q)
      {
          Q = (Queue)malloc(sizeof(SqQueue)*Max);
          Q->front = Q->rear = 0;
      }
      
      • 销毁队列
      void DestroyQueue(Queue Q)
      {
          free(Q);
      }
      
      • 判断队列是否为空
      bool QueueEmpty(Queue Q)
      {
          return (Q->front == Q->rear);
      }
      
      • 入队
      bool EnQueue(Queue Q,ElemType e)
      {
          if((Q->rear +1) % MaxSize == Q->front)
              return false;
          Q->data[Q->rear] = e;
          Q->rear = (Q->rear + 1) % MaxSize;
          return true;
      }
      
      • 出队
      bool DeQueue(Queue Q,ElemType &e)
      {
          if(Q->front == Q->rear)
              return false;
          e = Q->data[Q->front];
          Q->front = (Q->front + 1) % MaxSize;
          return true;
      }
      
    • 链队列的结构、操作函数

      • 结构体定义
      typedef struct QNode    /* 声明链式队列的结点 */
      {
          int data;
          struct QNode *next;
      }Node;
      typedef struct QueuePoint    /* 声明链式队列的首尾指针 */
      {
          Node *front;
          Node *rear;
      };
      typedef QueuePoint* Queue;
      
      • 初始化队列
      Queue InitQueue (Queue Q)    
      {                        
          Q = (Queue)malloc(sizeof(QueuePoint));
          Q->front = Q->rear = NULL;
      
          return Q;
      }
      
      • 销毁队列
      void DestroyQueue(Queue Q)
      {
          Node* pre = Q->front,* p;
          if(pre != NULL)
          {
              p = pre->next;
              while(p != NULL)
              {
                  free(pre);
                  pre = p;p = p->next;
              }
              free(pre);
          }
          free(Q);
      }
      
      • 判断队列是否为空
      bool QueueEmpty(Queue Q)
      {
          return (Q->rear == NULL);
      }
      
      • 入队
      void EnQueue(Queue Q,ElemType e)
      {
          Node* p;
          p = (Node*)malloc(sizeof(Node));
          p->data = e;
          p->next = NULL;
          if(Q->rear == NULL)
              Q->front = Q->rear = p;
          else
          {
              Q->rear->next = p;
              Q->rear = p;
          }
      }
      
      • 出队
      bool DeQueue(Queue Q,ElemType &e)
      {
          Node* p;
          if(Q->rear == NULL)
              return false;
          p = Q->front;
          if(Q->front == Q->rear)
              Q->front = Q->rear = NULL;
          else
              Q->front = Q->front->next;
          e = p->data;
          free(p);
          return true;
      }
      
    • 队列应用,要有具体代码操作。

      舞伴问题

      int QueueLen(SqQueue Q){//队列长度
      return (Q->rear -Q->front + MAXQSIZE ) % MAXQSIZE;
      
      }
      int EnQueue(SqQueue &Q, Person e){//入队
       Q->rear = (Q->rear + 1) %MAXQSIZE;
        	Q->data[Q->rear] = e;
        	return 0;
      }
      int QueueEmpty(SqQueue &Q){//判空
          if(Q->front==Q->rear){
              return 1;
          }else{
              return 0;
          }
      }
      int DeQueue(SqQueue &Q, Person &e){//出队
      //就很神奇,把出队那个存到e中
          Q->front=(Q->front+1)%MAXQSIZE;    
          e=Q->data[Q->front];
          return 0;
      }
      void DancePartner(Person dancer[], int num){
         /*
         *函数作用:
         *1.将Person里存的人分到Mdancers, Fdancers两个队列
         *2.Mdancers, Fdancers一比一配队出列
         */
         //Mdancers, Fdancers
         for(int i=0;i<num;i++){
          if(dancer[i].sex=='M'){
              EnQueue(Mdancers,dancer[i]);
          }else{
              EnQueue(Fdancers,dancer[i]);
          }
         }
         while(QueueEmpty(Mdancers)!=1&&QueueEmpty(Fdancers)!=1){
          Person x,y;
          DeQueue(Mdancers, x);
          DeQueue(Fdancers, y);
          cout<<y.name<<"  "<<x.name<<endl;
         }
      }
      
      

    2.PTA实验作业(4分)

    此处请放置下面2题代码所在码云地址(markdown插入代码所在的链接)。如何上传VS代码到码云

    2.1 符号配对

    #include<iostream>
    #include<string>
    #include<stack>
    using namespace std;
    int main() {
    	string s;
    	char b[7];
    	b[1] = '('; b[2] = ')'; b[3] = '['; b[4] = ']'; b[5] = '{'; b[6] = '}';//用来存储括号,省掉三分之二的代码量。如果你代码超过100行了,那很有可能是因为用了6个if而不是2个。
    	int find = 0;
    	bool isasimple = false;
    	stack<char> bracket;//特地百度了一下括号的英文单词,就用他做栈名字吧。
    	while (1) {
    		getline(cin, s);
    		if (s==".") goto zoulou;//当结束时,直接“zoulou”(走咯)
    		for (int i = 0; i < s.length(); i++) {//*/是两个字符比较特殊,单独讨论
    			if (s[i] == '/' && 1 + i < s.length())
    				if (s[i + 1] == '*') {
    					bracket.push(s[i]);//我们将两个字符以/的形式保存,这样方便
    					i++;//因为这时候是两个字符
    					continue;
    				}
    			if (s[i] == '*' && 1 + i < s.length())
    				if (s[i + 1] == '/')
    				{
    					if (bracket.empty()) {
    						cout << "NO" << endl << "?-*/" << endl;
    						return 0;
    					}
    					else {
    						if (bracket.top() != '/') {
    							cout << "NO" << endl << bracket.top() << "-?" << endl;
    							return 0;
    						}
    						else {
    							bracket.pop();
    							i++;//弹栈是弹一个,但是让栈弹的却是两个字符
    							continue;
    						}
    					}
    				}
    			isasimple = false;
    			for (find = 1; find <= 6; find++) {
    				if (b[find] == s[i]) {//找一下是不是剩余的六个字符
    					isasimple = true; break;
    				}
    			}
    			if (isasimple) {
    				if (find % 2 == 1) {
    					bracket.push(s[i]);
    					continue;
    				}
    				else {
    					if (bracket.empty()) {
    						cout << "NO" << endl << "?-" << b[find] << endl;
    						return 0;
    					}
    					else {
    						if (bracket.top() == '/') {
    							cout << "NO" << endl <<"/*-?" << endl;
    							return 0;
    						}
    						else if (bracket.top() != b[find - 1]) {
    							cout << "NO" << endl << bracket.top() << "-?" << endl;
    							return 0;
    						}
    						else {
    							bracket.pop();
    							continue;
    						}
    					}
    				}
    			}
    		}
    	}
    zoulou:
    	if (bracket.empty()) {//走咯之后还没完,如果栈不是空的,也还会出错。
    		cout << "YES" << endl;
    	}
    	else {
    		cout << "NO" << endl << bracket.top() << "-?" << endl;
    	}
    	return 0;
    }
    
    

    2.1.1 解题思路及伪代码

    • 当左边一堆左括号时,右边出现一个右括号,此右括号与离他最近的一个左括号匹配。 就是我们一直以右括号为标准,当右括号出现时,我们就要找他左边的括号。 所以我们要保存左括号,由于这个性质,我们可以用栈保存左括号。
    • 思路:我们一直把左括号压入栈中,当找到有个右括号时,我们把它和栈顶元素比较。
      但是比较的时候,要看栈是否为空。非空的话我们可以比较。如果为空,那我们就保存这个右符号,同时设置一个flag变量。
      最终还要看一看栈里面是不是空的,如果是空的,且flag也没问题,那我们输出yes
      如果栈为空,但是flag标记了,那我们输出那个右符号
      如果栈不是空的,输出栈顶即可。

    2.1.2 总结解题所用的知识点

    • 顺序栈的结构

    • 顺序栈的出栈入栈操作

    • 递归函数的调用

    • 标准输入输出流的运用

    • 使用了hash表的知识,用hash表来存储会用到的符号。

    • 使用了STL库的string类。

    • 学会了利用string类的特点对多行元素进行有指定结束标志的读取。

    2.2 银行业务队列简单模拟

    #include <stdio.h>
    int main() 
    { 
    	int a[1010], b[1010];   //数组a,b用来存放A,B窗口的顾客 
    	int ca = 0,cb = 0;     //ca,cb分别代表窗口A、窗口B的人数 
    	
    	int n; 	//n为顾客总数 	
    	scanf("%d", &n); 
    	for (int i = 1; i <= n; i++) 
    	{ 
    		int temp; //顾客编号 
    		scanf("%d", &temp);
    		
    		//编号为偶数的去A窗口 ,否则去B窗口 
    		if (temp % 2)  
    			a[++ca] = temp; 
    		else 
    		b[++cb] = temp; 
    	} 
    	
    	int f = 0;//控制空格的输出 
    	int x = 1, y = 1; //x,y为a[],b[]下标,从1开始遍历(模拟队列,先进先出)
    	 
    	//A优先输出,A出两个,B出一个 
    	while (x <= ca || y <= cb) 
    	{ 
    		if (x <= ca) 
    		{ 
    			if (f++) 
    				printf(" "); 
    			printf("%d", a[x++]); 
    		} 
    		if (x <= ca) 
    		{ 
    			if (f++) 
    				printf(" "); 
    			printf("%d", a[x++]); 
    		} 
    		if (y <= cb) 
    		{ 
    			if (f++) 
    				printf(" "); 
    			printf("%d", b[y++]); 
    		} 
    	} 
    	return 0; 
    	}
    

    2.2.1 解题思路及伪代码

    emm,很尴尬没有用队列和栈QwQ

    2.2.2 总结解题所用的知识点

    3.阅读代码(0--1分)

    1份优秀代码,理解代码功能,并讲出你所选代码优点及可以学习地方。主要找以下类型代码:

    注意:不能选教师布置在PTA的题目。完成内容如下。

    3.1 题目及解题代码

    可截图,或复制代码,需要用代码符号渲染。

    #include<iostream>
    #include <stack>
    char s[4] = { 'q','a','b','c' };
    std::stack<int> a[4];
    bool move(int before, int after) {
    	if (a[before].empty())
    		return false;
    	if (!a[after].empty())
    		if ((a[after].top() - a[before].top()) < 0)
    			return false;
    	a[after].push(a[before].top());
    	a[before].pop();
    	printf("%c -> %c
    ", s[before], s[after]);//faster than cout
    	return true;
    }
    int main() {
    	int  N, count = 0;
    	std::cin >> N;
    	for (int i = 0; i < N; i++)
    		a[1].push(N - i);
    	if (N % 2 == 1) {
    		s[2] = 'c'; s[3] = 'b';
    	}
    	while (++count) {
    		move((count - 1) % 3 + 1, (count) % 3 + 1);
    		if (!move((count - 1) % 3 + 1, (count + 1) % 3 + 1)&&!move((count + 1) % 3 + 1, (count - 1) % 3 + 1))
    				break;
    	}
    }
    

    3.2 该题的设计思路及伪代码

    链表题目,请用图形方式展示解决方法。同时分析该题的算法时间复杂度和空间复杂度

    所有的汉诺塔移动可以总结为重复的两步,我们假设现在最小的圆盘在a柱子上,柱子为a,b,c

    第一步:将最小圆盘移动到下一个柱子上,也就是b

    第二步:对a柱子和c柱子进行顶上最小的元素进行判断,把小一点的那个圆盘移动到大一点的那个圆盘(有空则摞在空柱子上)。

    重复上述两步就可以得到答案。

    注意:这样得到的最后的答案不一定是摞在c上,如果N是偶数将摞在b上,所以如果N是偶数我们就令第二个柱子为c,第三个柱子为b,这样就一定最后是摞在c上的。

    3.3 分析该题目解题优势及难点。

    真的有毒

  • 相关阅读:
    css之BFC和IFC
    关于移动端的适配问题
    前端构建工具gulp之实际应用
    前端构建工具gulp之基本介绍
    关于构造函数和原型prototype对象的理解
    Sublime Text 3的常用插件的安装和介绍
    Array对象的方法详情
    PHP中使用CURL实现GET和POST请求
    今天终于有空看看断点调试了
    ob_flush()和flush()的区别
  • 原文地址:https://www.cnblogs.com/WangBo020809/p/14643885.html
Copyright © 2011-2022 走看看