DS博客作业02--栈和队列

0.PTA得分截图

1.本周学习总结

1.1 栈

1.1.1栈的定义及相关概念

  • 栈是一种只能在一端进行插入或删除操作的线性表。

  • 允许进行插入、删除操作的一端称为栈顶。

  • 表的另一端称为栈底。

  • 当栈中没有数据元素时,称为空栈。

  • 栈的插入操作通常称为进栈或入栈,删除操作通常称为退栈或出栈。

1.1.2栈的存储结构

  • 顺序存储,如图所示

DS博客作业02--栈和队列_第1张图片

  • 链式存储,如图所示

1.1.2栈的结构体定义

代码:

typedef struct
{
    int data[MAXSIZE];
    int top;
}Stack;

1.1.3栈的初始化

代码:

SeqStack* InitStack()
{
    Stack* s;
    s = (Stack*)malloc(sizeof(Stack));
    s->top = -1;
    return s;
}

1.1.4入栈操作

代码:

int PushStack(Stack* s, int x)
{
    if(s->top == MAXSIZE - 1)
        return 0;
    else{
        s->top++;
        s->data[s->top] = x;
        return 1;
    }
}
  • 图解:

DS博客作业02--栈和队列_第2张图片
DS博客作业02--栈和队列_第3张图片

1.1.5出栈操作

代码:

int PopStack(Stack* s, int* x)
{
    if(EmptyStack(s))
        return 0;            //栈空不能出栈
    else
    {
        *x = s->data[s->top];
        s->top--;
        return 1;
    }
}
  • 图解:

DS博客作业02--栈和队列_第4张图片
DS博客作业02--栈和队列_第5张图片

1.1.6判断栈空操作

代码:

int EmptyStack(Stack* s)
{
    if(s->top == -1)
        return 1;
    else
        return 0;
}

1.1.7取栈顶元素操作

代码:

DataType GetTop(Stack* s)
{
    if(EmptyStack(s))
        return 0;            //栈空返回
    else
        return s->data[s->top];
}

1.1.8输出栈操作

代码:

int Print_SeqStack(SeqStack* s)
{
    int i;
    if(EmptyStack(s))
    {
        printf("空栈!\n");
        return 0;            //栈空返回
    }
    printf("当前栈中的元素:\n");
    for(i = s->top; i >= 0; i--)
        printf("%d ", s->data[i]);
    printf("\n");
    return 0;
}

1.1.9链栈

  • 定义:将链表的头部作为栈顶,尾部作为栈底

  • 链栈的结构体定义

代码:

typedef struct node
{    
     int data;          /*数据域*/      
     struct node * next;     /*指针域*/
 }LinkStack;  
  • 判断空栈

代码:

int StackEmpty(LinkStack *top)
{
    if(!top)
        return 0;
    else
        return 1;
}
  • 入栈操作,即将数据从链表的头部插入

代码:

LinkStack *Push(LinkStack *top,int x)
{
   LinkStack *p;
   p=(LinkStack *)malloc(sizeof(LinkStack));
   p->data=x;         /*设置新结点的值*/
   p->next=top;       /*将新元素插入栈中*/
   top=p;             /*将新元素设为栈顶*/
   return top;
}
  • 出栈操作,即删除链表头部的首元节点

代码:

LinkStack *Pop(LinkStack *top)
{
   LinkStack *p;
   if(!top)
   {
       printf("空栈!/n");
       return NULL;
   }
   p=top;  //指向被删除的栈顶
   top=top->next; //修改栈顶指针
   free(p);
   return top;
}
  • 取栈顶元素

代码:

int GetTop(LinkStack *top)
{
    if(!top)
    {
       printf("空栈!/n");
       return 0;       
    }
    return top->data;
}

1.2.1队列的定义及相关概念

  • 队列是一种运算受限的线性表,只能选取一个端点进行插入操作,另一个端点进行删除操作。

  • 进行插入(进队或入队)的一端称做队尾(rear)。

  • 进行删除(出队)的一端称做队首或队头(front)。

1.2.2队列的存储结构

  • 顺序存储,如图所示

  • 链式存储,如图所示

DS博客作业02--栈和队列_第6张图片

1.2.3队列的结构体定义

代码:

typedef struct 
{     
    int data[MaxSize]; 
    int front,rear;      
}Queue;

1.2.4队列的初始化

代码:

void InitQueue(Queue *&queue)
{   
q=(Queue *)malloc (sizeof(Queue));

  q->front=q->rear=-1;
}

1.2.5入队操作

代码:

int InQueue(Queue *&q,int e)
{        
    if (q->rear==MaxSize-1)	        //队满
    return 0;
    q->rear++;
    q->data[q->rear]=e;
    return 1;
}

1.2.6出队操作

代码:

int OutQueue(Queue *&q,int &e)
{      
    if (q->front==q->rear)  //队空
    return 0;
    q->front++;
    e=q->data[q->front];
    return 1;
}

1.2.7循环队列

  • 循环队列判空的条件是front=rear。

  • 循环队列判满的条件是front=(rear+1)%MaxSize。

  • 循环队列结构体定义

代码:

typedef struct 
{
    int *base; // 初始化的动态分配存储空间
    int front; // 头指针,若队列不空,指向队列头元素
    int rear; // 尾指针,若队列不空,指向队列尾元素的下一个位置
}SqQueue;
  • 循环队列初始化

代码:

Queue* InitQueue() 
{
    SqQueue *Q = (SqQueue*)malloc(sizeof(SqQueue));
    Q->base = (int *)malloc(MAX_QSIZE * sizeof(int));
    Q->front = Q->rear = 0;
    return Q;
}
  • 循环队列入队

代码:

int InQueue(Queue *Q, int e) 
{
    if ((Q->rear + 1) % MAX_QSIZE == Q->front) // 满队
        return 0;
    Q->base[Q->rear] = e;
    Q->rear = (Q->rear + 1) % MAXSIZE;
    return 1;
}
  • 循环队列出队

代码:

int OutQueue0(Queue *Q, int &e) 
{
    if (Q->front == Q->rear) // 空队
        return 0;
    e = Q->base[Q->front];
    Q->front = (Q->front + 1) % MAXSIZE;
    return 1;
}

1.2.8链队

  • 链队的结构体定义

代码:

typedef struct QNode
{
    int data;
    struct QNode * next;
}QNode;
  • 链队的初始化

代码:

QNode * initQueue()
{
    QNode * queue=(QNode*)malloc(sizeof(QNode));
    queue->next=NULL;
    return queue;
}
  • 链队入队操作

代码:

QNode* enQueue(QNode * rear,int data)
{
    QNode * temp=(QNode*)malloc(sizeof(QNode));
    temp->data=data;
    temp->next=NULL;
    rear->next=temp;
    rear=temp;
    return rear;
}
  • 链队出队操作

代码:

void DeQueue(QNode * top,QNode * rear)
{
    if (top->next==NULL) 
    {
        printf("队列为空");
        return ;
    }
    QNode * p=top->next;
    printf("%d",p->data);
    top->next=p->next;
    if (rear==p) 
        rear=top;
    free(p);
}

1.3.栈和队列的认识及学习体会

怎么说呢,感觉这次PTA的题目挺难的,要么没思路,要么就是各种调试错误,还是要认真啊。栈跟队列具有很特殊的性质,一个是“先进后出”,一个是只准队首出,队尾入,此外还有链栈、链队、循环队列等,相信运用好这些特性并加以组合定会解决一些难题,获得意想不到的的效果。总之,还是要多多编程,好好编程。

2.PTA实验作业

2.1.题目1:银行业务队列简单模拟

DS博客作业02--栈和队列_第7张图片
DS博客作业02--栈和队列_第8张图片

2.1.2本题PTA提交列表说明

DS博客作业02--栈和队列_第9张图片

  • 编译错误:选错了编译器。

  • 多种错误:有段错误、格式错误,以下我展开叙述。

  • 段错误:定义str[MaxSize]数组时MaxSize 值取得偏小,改为1000即可。

  • 格式错误:没看见题干中“但最后一个编号后不能有多余的空格”一句,后将代码改成:

DS博客作业02--栈和队列_第10张图片

但这并不能解决问题,反而造成部分测试点答案错误。

  • 部分正确:部分测试点显示答案错误,由于在输出Q2数据时也应将i加一,因此i就不能作为判断是否轮到Q2输出的变量,因此另设count作为判断变量,测试点就全过了。

2.2 题目2字符串是否对称

DS博客作业02--栈和队列_第11张图片

2.1.2本题PTA提交列表说明

  • 部分正确:“对称字符串”这一测试点无法通过,经查,为以下错误代码:

DS博客作业02--栈和队列_第12张图片

因为没有在for循环内添加出栈语句,导致str[i]一直在与同一个栈顶数据相比较,结果把所有字符串全判为不对称,补充st.pop()一句便通过了测试点。

3.阅读代码

3.1 题目及解题代码

  • 题干:

DS博客作业02--栈和队列_第13张图片

  • 代码:

DS博客作业02--栈和队列_第14张图片

3.1.1 该题的设计思路

  • 思路:1.引入一个栈stack。2.把pushed序列按顺序放到栈stack中,每放一个数据对比栈顶与序列popped中元素是否相同,若相同,则栈stack执行pop操作,移到popped的下一个元素,继续对比栈顶与该元素是否相同。

  • 正确案例图解:

DS博客作业02--栈和队列_第15张图片

  • 错误案例图解:

DS博客作业02--栈和队列_第16张图片

  • 时间复杂度:以正确的序列为例,假设pushed 和 popped 两个序列的长度为n,则for循环中必定要跑n趟才能将pushed中的所有元素入s栈,而在while循环中也必定需要n趟才能实现s空栈,所以,总次数为2n次,即时间复杂度为O(n)。

  • 空间复杂度:O(n)。

3.1.2 该题的伪代码

int n=popped.size();    /*获取序列的大小*/
int i;                 //用于for循环
stack s;           //存放pushed元素
int k=0;                //用于统计有几个s栈顶元素与popped首元素相同
for i=0 to i

3.1.3 运行结果

DS博客作业02--栈和队列_第17张图片

3.1.4分析该题目解题优势及难点

  • 解题优势:思路很棒,利用了栈先进后出的特点仅用两层循环就解决了验证栈的序列,总体代码量也较少,时间及空间复杂度较低。

  • 本题难点:给出栈的入栈次序判断栈的出栈次序是否合理本身就是个难点,栈的出栈次序存在着多种组合,编程思路就难稿。

3.2 题目及解题代码

  • 题目:

DS博客作业02--栈和队列_第18张图片

  • 代码:

DS博客作业02--栈和队列_第19张图片

3.2.1 该题的设计思路

  • 思路:

先排序,然后插入。
假设候选队列为 A,已经站好队的队列为 B.
从 A 里挑身高最高的人 x 出来,插入到 B. 因为 B 中每个人的身高都比 x 要高,因此 x 插入的位置,就是看 x 前面应该有多少人就行了。比如 x 前面有 5 个人,那 x 就插入到队列 B 的第 5 个位置。

  • 图解:

DS博客作业02--栈和队列_第20张图片

  • 时间复杂度:两次遍历,一次排序,一次插入,所以时间复杂度为O(n)

  • 空间复杂度:O(n)

3.2.2 该题的伪代码

将people按照身高降序排序,相同身高需要按k升序排序
开辟e,将排序后的people存入e
开辟res
for 遍历e
    找到位置后插入res
end for
返回res

3.2.3 运行结果

DS博客作业02--栈和队列_第21张图片

3.2.4分析该题目解题优势及难点

  • 优点:思路很棒 ,代码也很简洁,sort、vector语法运用自如。

  • 难点:单按h排序并不难,难在还要考虑k的存在。

你可能感兴趣的:(DS博客作业02--栈和队列)