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

0.PTA得分截图

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

1.1 栈

画一个栈的图形,介绍如下内容。
栈的定义:栈是一种只能在一端进行插入或删除操作的线性表。栈又称为后进先出的线性表,其中有几个名词:栈顶、栈底、空栈。
栈顶:允许插入和删除的一端。
栈底:不允许插入和删除的一端。
空栈:表中没有元素。

进栈出栈规则:
栈顶出栈->栈底最后出栈;
时进时出->元素未完全进栈时,即可出栈。
顺序栈的结构、操作函数

顺序栈定义结构体:

typedef struct
{
  ElemType data[MaxSize];  //存放栈中的数据元素
  int top;                 //栈顶指针,即存放栈顶元素在data数组中的下标
}SqStack;                  //顺序栈的类型

初始化顺序栈:

void InitStack(SqStack *&s)
{
  s=new SqStack;   //分配一个顺序栈空间,首地址存放在s中
  s->top=-1;       //栈顶指针置为-1,即栈空
}

销毁顺序栈:

void DestroyStack(SqStack *&s)
{
  free(s);
}

判断顺序栈是否为空:

bool StackEmpty(SqStack * s)
{
  return(s->top==-1);
}

元素进入顺序栈:

bool Push(SqStack *&s,ElemType e)
{
   if(s->top==MaxSize-1)   //栈满情况,即栈上溢出
        return false;
   s->top++;              //栈顶指针增1
   s->data[s->top]=e;     //元素e放在栈顶指针处
   return true;
}

元素出顺序栈:

bool Pop(SqStack *&s,ElemType &e)
{
  if(s->top==-1)     //栈为空的情况,即栈下溢出
     return false;
  e=s->data[s->top]; //取出栈顶元素
  s->top--;          //栈顶指针减1
  return true;
}

取顺序栈中栈顶元素:

bool GetTop(SqStack *&s,ElemType &e)
{
   if(s->top==-1)    //栈为空的情况,即栈下溢出
       return false;
   e=s->data[s->top];  //取栈顶元素
   return true;
}

共享栈:合并两个栈,用一个数组实现两个栈。

共享栈四要素:
栈空条件:栈1空为top1==-1;栈2空为top2==MaxSize。
栈满条件:top1==top2-1;
元素x进栈操作:进栈1操作为top1++;data[top1]=x;进栈2操作为top2--;data[top2]=x。
出栈x操作:出栈1操作为x=data[top1];top1--;出栈2操作为x=data[top2];top2++。
共享栈结构体:

typedef struct
{
  ElemType data[MaxSize]; //存放共享栈中的元素
  int top1,top2;          //两个栈的栈顶指针
}DStack;                  //共享栈的类型

链栈的结构、操作函数

链栈的结构体:

typedef struct linknode
{
   ElemType data;         //数据域
   struct linknode *next; //指针域
}LinkStNode;              //链栈结点类型

初始化链栈:

void InitStack(LinkStNode *&s)
{
   s=new LinkStNode;
   s->next=NULL; //栈空
}

销毁链栈:

void DestroyStack(LinkStNode *&s)
{
   LinkStNode * pre=s,*p=s->next; //pre指向头结点,p指向首结点
   while(p!=NULL)                 //循环到p为空
    {
      free(pre);                  //释放pre结点
      pre=p;                      //pre、p同步后移
      p=pre->next;                
    }
    free(pre);                   //此时pre指向尾结点,释放其空间
}

判断链栈是否为空:

bool StackEmpty(LinkStNode *s)
{
    return (s->next=NULL);
}

元素进入链栈:

void Push(LinkStNode *&s,ElemType e)
{
   LinkStNode *p;    
   p=new LinkStNode; //新建结点p
   p->data=e;        //存放元素e
   p->next=s->next;  //将p结点插入作为首结点
   s->next=p;
}

元素出链栈:

bool Pop(LinkStNode *&s,ElemType &e)
{
   LinkStNode * p;
   if(s->next==NULL)  //栈空情况
       return false;
   p=s->next;        //p指向首结点
   e=p->data;        //提取首结点值
   s->next=p->next;  //删除首结点
   free(p);          //释放被删除结点的存储空间
   return true;
}

取链栈栈顶元素:

bool GetTop(LinkStNode *&s,ElemType &e)
{
   if(s->next==NULL) //栈空情况
      return false;
   e=s->next->data; //提取其首结点值
   return true; 
}

1.2 栈的应用

问题:
exp="1+2(4+12)";
做法:
1.转后缀表达式
2.后缀表达式求值
中缀表达式:运算符号位于两个运算数之间。如:a+b
c-d/e
后缀表达式:运算符号位于两个运算数之后。如:abc*+de/-

将算式exp转化成后缀表达式postexp:

void trans(char * exp,char postexp[])
{
   cahr e;
   SqStack * Optr;
   InitStack(Optr);
   int i=0;
   while(*exp!='\0')
    {
      switch(*exp)
       {
         case '(':
              Push(Optr,'(');
              exp++;
              break;
         case ')':
              Pop(Optr,e);
              while(e!='(')
               {
                 postexp[i++]=e;
                 Pop(Optr,e);
               }
               exp++;
               break;
        case '+':
        case '-':
             while(!StackEmpty(Optr))
              {
                GetTop(Optr,e);
                if(e!='(')
                 {
                   postexp[i++]=e;
                   Pop(Optr,e);
                 }
                else
                   break;
              }
             Push(Optr,*exp);
             exp++;
             break;
        case '*':
        case '/':
             while(!StackEmpty(Optr))
                {
                  GetTop(Optr,e);
                  if(e=='*'||e=='/')
                    {
                      postexp[i++]=e;
                      Pop(Optr,e);
                    }
                  else
                     break;
                }
            Push(Optr,*exp);
            exp++;
            break;
        default:
             while(*exp>='0'&&*exp<='9')
                {
                  postexp[i++]=*exp;
                  exp++;
                }
                postexp[i++]='#';
       }
    } 
    while(!StackEmpty(Optr))
       {
         Pop(Optr,e);
         postexp[i++]=e;
       }
       postexp[i]='\0';
       DestroyStack(Optr);
}

1.3 队列

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

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

顺序队列的结构体:

typedef struct
{
  ElemType data[MaxSize]; //存放队中的元素
  int front,rear;         //队头和队尾指针
}SqQueue;                 //顺序队类型

初始化顺序队列:

{
  q=new SqQueue;
  q->front=q->rear=-1;
}

销毁顺序队列:

void DestroyQueue(SqQueue *&q)
{
  free(q);
}

判断顺序队列是否为空:

bool QueueEmpty(SqQueue *q)
{
  return (q->front==q->rear);
}

元素进入顺序队列:

bool enQueue(SqQueue *&q,ElemType e)
{
  if(q->rear==MaxSize-1)  //队列满上溢出
     return false;
  q->rear++;             //队尾增1
  q->data[q->rear]=e;    //rear位置插入元素e
  return true;
}

元素出顺序队列:

bool deQueue(SqQueue *&q,ElemType &e)
{
   if(q->front==q->rear)   //队列空下溢出
      return false;
   q->front++;             //队头增1
   e=q->data[q->front];    //front位置出队列
   return true;
}

环形队列的结构、操作函数

初始化环形队列:

void InitQueue(SqQueue *&q)
{
  q=new SqQueue;
  q->front=q->rear=0;
}

销毁环形队列:

void DestroyQueue(SqQueue *&q)
{
   free(q);
}

判断队列是否为空:

bool QueueEmpty(SqQueue *q)
{
   return (q->front==q->rear);
}

元素进入环形队列:

bool enQueue(SqQueue *&q,ElemType e)
{
   if((q->rear+1)%MaxSize==q->front) //队列满上溢出
      return false;
   q->rear=(q->rear+1)%MaxSize;     
   q->data[q->rear]=e;
   return true;
}

元素出环形队列:

bool deQueue(SqQueue *&q,ElemType &e)
{
    if(q->front==q->rear)          //队列空下溢出
       return false;
    q->front=(q->front+1)%MaxSize;
    e=q->data[q->front];
    return true;
}

链队列的结构、操作函数

链队列的结构体:

typedef struct qnode
{
  ElemType data;     //存放元素
  struct qnode *next;//下一个结点指针
}DataNode;           //链队数据结点的类型

链队头结点类型LinkQuNode:

typedef struct
{
  DataNode *front; //指向队首结点
  DataNode *rear;  //指向对尾结点
}LinkQuNode;       //链队结点的类型

初始化链队:

void InitQueue(LinkQuNode *&q)
{
     q=new LinkQuNode;
     q->front=q->rear=NULL;
}

销毁链队:

void DestroyQueue(LinkQuNode *&q)
{
     DataNode *pre=q->front,*p;  //pre指向队首结点
     if(pre!=NULL)
       {
         p=pre->next;           //p指向结点pre的后续结点
         while(p!=NULL)         //p不为空时循环
              {
                free(pre);     //释放pre结点
                pre=p;         //pre后移
                p=p->next;     //p后移
              }
         free(pre);            //释放最后一个数据结点
      }
     free(q);                 //释放链队结点
}

判断链队是否为空:

bool QueueEmpty(LinkQuNode *q)
{
     return (q->rear==NULL);
}

元素进入链队:

void enQueue(LinkQuNode *&q,ElemType e)
{
    DataNode *p;
    p=new DataNode;        //创建新结点
    p->data=e;
    p->next=NULL;
    if(q->rear==NULL)      //若链队为空,则新结点既是队首结点又是对尾结点
       q->front=q->rear=p;
    else                  //若链队不空
   {
        q->rear->next=p;  //将结点p链到对尾,并将rear指向它
        q->rear=p;
   }
}

元素出链队:

bool deQueue(LinkQuNode *&q,ElemType &e)
{
     DataNode *t;
     if(q->rear==NULL)          //原来队列为空
        return false;
     t=q->front;                //t指向首结点
     if(q->front==q->rear)      //原来队列只有一个数据结点时
        q->front=q->rear=NULL;
     else                       //原来队列中有两个或两个以上结点时
        q->front=q->front->next;
     e=t->data;
     free(t);
     return true;
}

队列应用,要有具体代码操作。

2.PTA实验作业(4分)

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

2.1 符号配对

2.1.1 解题思路及伪代码

解题思路:定义flag进行判断操作,输入左符号时入栈,输入右符号时并且判断栈里面是否有元素,若无则为一种情况,若有则进行配对,判断是否是该右符号对应的左符号,用flag标记对应的情况。
伪代码:

int flag=0;
for (遍历条件)
{
	if (为左符号)
	{
		入栈;
	}
	else if (栈为空且有右符号)
	{
		flag = 1;
		break;
	}
	else if (各自左符号与右符号配对情况)
	{
		出栈;
	}
}
if (flag == 1)
{
	右符号剩余;
}
else if (栈为空)
{
	匹配;
}
else
{
	正常情况的不匹配;
}

2.1.2 总结解题所用的知识点

    • 宏定义,结构体,函数分装等
    • 申请空间用malloc动态申请。
    • 使用了链的存储功能,并且还使用了静态字符数组定义。

2.2 银行业务队列简单模拟

2.2.1 解题思路及伪代码

解题思路:
先判断编号的奇偶,若为奇数进A队列,若为偶数进B队列,再分别计算A队列和B队列的元素个数,后判断A无元素和只有1个元素的特殊情况,两种情况下再判断B的个数,之后普通情况,另A的元素个数除以2,因为2人为一组,1组输出2个编号后B输出1个编号,但要考虑到A的元素个数为奇数个,故要添加判断,若其为奇数最后一组输出1个。
伪代码:

for (遍历条件)
{
	if (编号为奇数)
	{
		进A;
	}
	else
	{
		进B;
	}	
}
统计A和B的个数
if (A个数为0)
{
	全部输出B元素;
}
else if (A元素个数为1)
{
	输出A;
	全部输出B;
}
else
{
	int i = A个数 / 2;
	for (n = 1; n <= i; n++)
	{
		if (n < i)
		{
			输出A2个元素;
		}
		else if (n == i && A个数为奇数)
		{
			输出A1个元元素;
		}
		else if (n == i && A个数为偶数)
		{
			输出A2个元素;
		}
		if (B还有元素)
		{
			输出B1个元素;
		}
	}
}

2.2.2 总结解题所用的知识点

    • queue相关函数的使用
    • 队列优先输出的顺序
    • 本题需要考虑A对列的特殊情况,考虑其个数以及奇偶性。

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

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

考研题
ACM题解
leecode--栈
leecode--队列
注意:不能选教师布置在PTA的题目。完成内容如下。

3.1 题目及解题代码

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

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

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

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

posted on 2021-04-05 22:44  jioky  阅读(54)  评论(0编辑  收藏  举报