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

    0.PTA得分截图

    1.本周学习总结

    1.1 总结栈和队列内容

    思维导图

    • ·栈的存储结构及操作
      栈:一种运算受限的线性表。其限制是仅允许在表的一端进行插入和删除运算,对于栈的操作有进栈,出栈,销毁栈,初始化栈与取栈顶元素。栈最需要注意的是栈是后进先出表。
    顺序栈
    
    typedef struct
    {
    	ElemType str[MaxSize];
    	int top;
    }SqStack;
    void InitStack(SqStack*& st)            //初始换栈
    {
    	st = new SqStack;
    	st->top = -1;
    }
    bool Push(SqStack*& st, ElemType string)            //入栈
    {
    	int i;
    	if (st->top == MaxSize - 1)
    	{
    		return false;
    	}
    	else
    	{
    		st->top++;
    		st->str[st->top] = string;
    		return true;
    	}
    }
    bool Pop(SqStack*& st, ElemType& e)                //出栈
    {
    	if (st->top == -1)
    	{
    		return false;
    	}
    	else
    	{
    		e = st->str[st->top];
    		st->top--;
    		return true;
    	}
    }
    
    
    链栈
    
    typedef struct SNode {
    	int data;
    	SNode *next;
    }SNode;
    typedef struct
    {
    	SNode *top;
    }LStack;
    void initLStack(LStack &S)             //初始化链栈
    {
    	S.top = new SNode;
    	S.top->data = NULL;
    	S.top->next = NULL;
    	return;
    }
    bool Empty(LStack S)             //判断栈是否为空
    {
    	if (S.top->next)
    		return false;
    	else
    		return true;
    }
    void push(LStack &S,int e)             //入栈
    {
    	SNode* newNode = new SNode;
    	newNode->data = e;
    	newNode->next = S.top->next;
    	S.top->next = newNode;
    	S.top->data++;
    	return;
    }
    
    bool popLStack(LStack &S)                 //出栈
    {
    	int e;
    	if (isEmptyLStack(S)) 
            {
                    return false;
    	}
    	SNode* delNode = S.top->next;
    	S.top->next = delNode->next;
    	e = delNode->data;
    	delete delNode;
    	S.top->data--;
    	return true;
    }
    
    • ·栈的应用
    检测括号是否匹配
    
    #include<stdio.h>
    #include<iostream>
    #include<string.h>
    #include<stack>
    using namespace std;
    #define Max 80
    typedef int ElementType;
    bool judge(string str);
    
    int main()
    {
    	string str;
    	cin >> str;
    	if (judge(str))
    		cout << "yes";
    	else
    		cout << "no";
    	return 0;
    }
    
    bool judge(string str)
    {
    	char e;
    	stack<char>st;
    	int flag = 1, i = 0;
    	while (str[i])
    	{
    		if (str[i] == '(' || str[i] == '[' || str[i] == '{')
    			st.push(str[i]);
    		else if (str[i] == ')' || str[i] == ']' || str[i] == '}')
    		{
    			if (st.empty())
    				return false;//如果栈已空,没有俞左括号配对,则错误
    			e = st.top();//取栈顶
    			st.pop();//去栈顶
    			switch (str[i])
    			{
    			case')':if (e != '(')flag = 0; break;
    			case']':if (e != '[')flag = 0; break;
    			case'}':if (e != '{')flag = 0; break;
    			}
    		}
    		i++;
    	}
    	if (st.empty() && flag == 1)
    		return true;//如果栈已经空了那就是对的
    	else
    	{
    		e = st.top();
    		cout << e << endl;
    		return false;
    	}
    }
    
    
    递归
    
    int fun(int n)//计算斐波那契数列第n项的值
    {
           if(n==1||n==2)
        {
                  return 1;
        }
        else
        {
                  return fun(n-1)+fun(n-2);
        }
    }
    
    
    
    int fun(int n)//n的阶乘
    {
           if(n==1)
        {
                  return 1;
        }
        else
        {
                  return fun(n-1)*n;
        }
    }
    
    进制转换
    
    bool Conversion(stack& s,int data,int N)
    {
         if(N<=0)
         {
            return false;
         }
         while (data)
         {
             push(s,data%N);
             data = data/N;
         }
    
         while (s)
         {
             pop(s);
         }
        return true;
     }
    
    • ·队列的存储结构及操作
    顺序队
    
    #define MaxSize 10  //队列的最大容量
    typedef int DataType;  //队列中元素类型
    typedef struct Queue
    {
        DataType Queue[MaxSize];
        int fornt;   //队头指针
        int rear;    //队尾指针
    }SeqQueue;
    
        
    void InitQueue(SeqQueue *SQ)        //队列初始化,将队列初始化为空队列
    {
        SQ->fornt = SQ->rear = 0;  //把对头和队尾指针同时置0
     }
    
        
    
    int IsEmpty(SeqQueue* SQ)            //判断队列为空
    {
        if (SQ->fornt == SQ->rear)
        {
            return 1;
        }
        return 0;
    }
    
    
    
    int IsFull(SeqQueue* SQ)        //判断队列是否为满
    {
        if (SQ->rear == MaxSize) 
        {
            return 1;
        }
        return 0;
    }
    
    
    void EnterQueue(SeqQueue* SQ,DataType data)        //入队,将元素data插入到队列SQ中
    
    {
        if (IsFull(SQ))
        {
            printf("队列已满
    ");
            return 0;
        }
        SQ->Queue[SQ->rear] = data;  //在队尾插入元素data
        SQ->rear = SQ->rear + 1;     //队尾指针后移一位
    }
    
    
    int DeleteQueue(SeqQueue* SQ,DataType* data)        //出队,将队列中队头的元素data出队,出队后队头指针front后移一位
    {
        if (IsEmpty(SQ))
        {
            printf("队列为空!
    ");
            return 0;
        }
        *data = SQ->Queue[SQ->fornt];   //出队元素值
        SQ->fornt = (SQ->fornt)+1;      //队尾指针后移一位
        return 1;
    }
    
    
    
    int GetHead(SeqQueue* SQ,DataType* data)        //获取队首元素
    {
        if (IsEmpty(SQ))
        {
            printf("队列为空!
    ");
        }
        return *data = SQ->Queue[SQ->fornt];  
    }
    
    
    
    void DestoryQueue(SeqQueue* SQ)            //销毁链表
    {
        SQ->fornt = SQ->rear = 0;
    }
    
    
    void PrintQueue(SeqQueue* SQ)        //打印队列中的与元素
    
    {
        assert(SQ);    
        int i = SQ->fornt;
        while(i<SQ->rear)
        {
            printf("%-3d", SQ->Queue[i]);
            i++;
        }
        printf("
    ");
    }
    
    链队
    
    typedef struct QueueNode
    {
        int e;//数据域
        struct QueueNode* next;//指针域
    }QueueNode,*LinkQueuePoi;
    typedef struct LinkQueue
    {
        LinkQueuePoi front;//指向头结点
        LinkQueuePoi rear;//指向队尾
    }LinkQueue;
    
    
    Status InitLinkQueue(LinkQueue* queue)        //初始化链队列.链队列为空时,链队列队头指针队尾指针均指向头结点
    {
        //空指针
        if (!queue)
        {
            return false;
        }
        QueueNode* node = (QueueNode*)malloc(sizeof(QueueNode));//头结点
        node->next = NULL;
        queue->front = queue->rear = node;
        return true;
    }
    Status CleaerLinkQueue(LinkQueue* queue)
    {
        //空指针
        if (!queue)
        {
            return false;
        }
        //空链队列
        if (queue->front == queue->rear)
        {
            return false;
        }
        QueueNode* node = queue->front->next;//队头元素
        while (node)
        {  
            queue->front->next = node->next;//指向新的队头结点
            if (queue->rear == node)//当删除的是队尾元素时,将队尾指针指向头结点
            {
                queue->rear = queue->front;
            }
            free(node);//释放旧的队头结点
            node = queue->front->next;
        }
        return true;
    }
    
    Status EmptyLinkQueue(LinkQueue* queue)        //判断链队列是否为空队列
    {
        //空指针
        if (!queue)
        {
            return ERROR;
        }
        //空链队列
        if (queue->front == queue->rear)
        {
            return    ;
        }
            return false;
    }
        /*
        获取链队列长度
        */
    int LengthLinkQueue(LinkQueue* queue)
        {
        //空指针
        if (!queue)
        {
            return false;
        }
        //空链队列
        if (queue->front == queue->rear)
        {
            return 0;
        }
        QueueNode* node = queue->front->next;
        int num = 0;
        while (node)
        {
            node = node->next;
            num++;
        }
        return num;
    }
    
    bool AddQueue(LinkQueue* queue,EleType e)            //在链队列队尾添加元素,先将新元素添加到链表尾部,然后将队列尾指针指向这个新元素
    {
        //空指针
        if (!queue)
        {
            return flase;
        }
        QueueNode* node = (QueueNode*)malloc(sizeof(QueueNode));
        if (!node)
        {
            return false;
        }
        node->next = NULL;
        node->e = e;
        queue->rear->next = node;//将新结点添加到链表表中
        queue->rear = node;//队尾指针指向新的队尾结点
        return true;
    }
    Status DelQueue(LinkQueue* queue, EleType *e)            //从链队列中删除队头元素,先将头结结点指向新的队头结点,然后释放原来的队头结点
    {
        //空指针
        if (!queue)
        {
            return false;
        }
        //注意queue->front是头结点,头结点指向的结点才是队头结点
        QueueNode* node = queue->front->next;//旧队头结点
        *e = node->e;
        queue->front->next = node->next;//队头指针指向新的队头结点
        //当删除的是队尾元素时,将队尾指针指向头结点
        if (node = queue->rear)
        {
               queue->rear = queue->front;
        }
        return  true;
    }
    void PrintfLinkQueue(LinkQueue* queue)            //输出链表
    {
         if (!queue)
         {
             return;
         }
         QueueNode* node = queue->front->next;
         while (node)
         {
             printf("%d,", node->e);
             node = node->next;
         }
         printf("
    ");
         return;
    }
    
    • ·队列应用
    广度优先搜索解决迷宫问题
    
    #include<iostream>
    #define MAX 1000
    using namespace std;
    
    int m, n;
    int mg[MAX][MAX];
    int xi, yi, xe, ye;
    typedef struct
    {
    	int i, j;
    	int pre;
    }BOX;
    
    typedef struct
    {
    	BOX data[MAX];
    	int front, rear;
    }QuType;
    
    void InitQueue(QuType*& qu);
    bool QueueEmpty(QuType* qu);
    void enQueue(QuType*& qu, BOX& e);
    void deQueue(QuType*& qu, BOX& e);
    void InitMg(int mg[][MAX]);
    void DestroyQueue(QuType*& qu);
    void count(QuType* qu, int front);
    bool mgpathl(QuType*& qu, int xi, int yi, int xe, int ye);
    
    int main()
    {
    
    	QuType* qu;
    	InitQueue(qu);
    	InitMg(mg);
    	cin >> xi >> yi;
    	cin >> xe >> ye;
    	mgpathl(qu, xi, yi, xe, ye);
    	return 0;
    }
    void InitMg(int mg[][MAX])
    {
    	int num;
    	cin >> m >> n;
    
    	for (int i = 0; i <= 1 + m; i++)
    	{
    		for (int j = 0; j <= 1 + n; j++)
    		{
    			if (i == 0 || j == 0 || i == m + 1 || j == 1 + n)
    			{
    				mg[i][j] = 1;
    			}
    		}
    	}
    	for (int i = 1; i <= m; i++)
    	{
    		for (int j = 1; j <= n; j++)
    		{
    			cin >> num;
    			mg[i][j] = num;
    		}
    	}
    }
    
    void InitQueue(QuType*& qu)
    {
    	qu = new QuType;
    	qu->front = -1;
    	qu->rear = -1;
    }
    void enQueue(QuType*& qu, BOX& e)
    {
    	qu->rear++;
    	qu->data[qu->rear] = e;
    }
    
    void deQueue(QuType*& qu, BOX& e)
    {
    	qu->front++;
    	e = qu->data[qu->front];
    }
    
    bool QueueEmpty(QuType* qu)
    {
    	if (qu->rear == -1)return true;
    	else return false;
    }
    void DestroyQueue(QuType*& qu)
    {
    	free(qu);
    }
    void count(QuType* qu, int front)                        //寻找出迷宫最短路径
    {
    	int k = front, j, ns = 0;
    	do
    	{
    		j = k;
    		k = qu->data[k].pre;
    		qu->data[j].pre = -1;
    	} while (k != 0);
    	k = 0;
    	while (k < MAX)
    	{
    		if (qu->data[k].pre == -1)
    		{
                            printf("(%d,%d)->", qu->data[k].i, qu->data[k].j);
    			ns++;
    		}
    		k++;
    	}
    	cout << ns;
    }
    
    bool mgpathl(QuType*& qu, int xi, int yi, int xe, int ye)            //寻找出迷宫路径
    {
    	BOX e;
    	int il,jl;
    	int i, j, find = 0, di;
    	e.i = xi;
    	e.j = yi;
    	e.pre = -1;
    	enQueue(qu, e);
    	mg[xi][yi] = -1;
    	while (qu->front != qu->rear && !find)
    	{
    		deQueue(qu, e);
    		i = e.i;
    		j = e.j;
    		if (i == xe && j == ye)
    		{
    			find = 1;
    			count(qu, qu->front);
    			return true;
    		}
    		for (di = 0; di < 4; di++)
    		{
    			for (di = 0; di < 4; di++)
    			{
    				switch (di)
    				{
    				case 0:il = i - 1; jl = j; break;
    				case 1:il = i; jl = j + 1; break;
    				case 2:il = i + 1; jl = j; break;
    				case 3:il = i, jl = j - 1; break;
    				}
    				if (mg[il][jl] == 0)
    				{
    					e.i = il;
    					e.j = jl;
    					e.pre = qu->front;
    					enQueue(qu, e);
    					mg[il][jl] = -1;
    				}
    			}
    		}
    	}
    	return false;
    }
    

    1.2.谈谈你对栈和队列的认识及学习体会

    栈和队列相较于前一部分学的线性表,学习难度有所增大,可现的功能更多。在使用线性栈和线性队列时,需要考虑栈和队列是否为满。
    而使用链栈和链队时,我们则不需要考虑栈或队列满的情况。
    循环队列的空满判断条件需要对最大空间进行取余。

    2.PTA实验作业

    2.1.题目1:7-8 电路布线

    2.1.1代码截图(注意,截图,截图,截图。不要粘贴博客上。)




    2.1.2本题PTA提交列表说明。


    Q1:代码虽然找到了出迷宫路径,但是该路径并非最短路径
    A1:发现是在寻找最短路径时,判断出了错误
    Q2:复制代码到PTA时少复制了一个头文件
    A2:重新复制了一遍

    2.2.题目2:银行排队问题之单队列多窗口服务

    2.1.1代码截图(注意,截图,截图,截图。不要粘贴博客上。)



    2.1.2本题PTA提交列表说明。


    Q1:三次错误原因相同,在统计等待时间时出了问题,在等待时,一开始统计了所有窗口的等待时间
    A2:改后,一个人只统计最短窗口的等待时间

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

    3.1 列车调度

    两端分别是一条入口(Entrance)轨道和一条出口(Exit)轨道,它们之间有N条平行的轨道。每趟列车从入口可以选择任意一条轨道进入,最后从出口离开。在图中有9趟列车,在入口处按照{8,4,2,5,3,9,1,6,7}的顺序排队等待进入。如果要求它们必须按序号递减的顺序从出口离开,则至少需要多少条平行铁轨用于调度?

    3.1.1 该题的设计思路


    T=O(n)
    S=O(1)

    3.1.2 该题的伪代码

    定义字符数组str1,str2
    输入1,2号铁轨列车顺序
    建栈S
    定义指针数组way
    while(str1[i]!='')
        如果 str1[i]与str2[j]相等
            路径为1->2
        如果栈顶与str2[j]相等
            路径为3->2,栈顶元素出栈
        如果str1[i]与str2[j]不相等
            路径为1->3,str[i]入栈
    如果S不为空
        while栈S不为空
           遍历str2余下元素
                如果flag==0而且栈顶元素与str2[t]相等
                    路径为3->2,出栈
                否则flag=1,出栈
    如果flag为0,输出指针数组way
    否则输出Are you kidding me?
    

    3.1.3 运行结果


    没看出来错在哪,第一个数据不对。

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

    加强了对栈空栈满的判断。

    3.2 用一个栈实现另一个栈的排序

    一个栈中元素的类型为整型,现在想将该栈从顶到底按从大到小的顺序排序,只许申请一个栈。除此之外,可以申请新的变量,但不能申请额外的数据结构。如何完成排序?

    3.2.1 该题的设计思路

    题中给出了两个栈,我们可以将要排序的栈记为stack,辅助栈记为help。要实现stack中的元素从顶到底按从大到小排序,则入栈的元素顺序应该为:从小到大。所以,help栈中元素从顶到底要实现由小到大的顺序。那么这就是解题关键了,我们只要实现这个就好。
    T=O(n)
    S=O(n)

    3.2.2 该题的伪代码

    在stack上执行pop操作,弹出的元素记为cur。
    若cur小于或者等于help的栈顶元素,则将cur直接压入help。
    (!!!保持help从栈顶到栈底由小到大的顺序)
    2.若cur大于help的栈顶元素(注意:若此时将cur压入help,则会违反help栈
    顶到底由小到大的顺序),则将help的元素逐一弹出,逐一压入stack,直到cur小于
    或者等于help的栈顶元素,再将cur压入help。
    3.重复以上操作,直到stack中的全部元素都压入到help。最后将help中的所有
    元素逐一压入stack,即完成排序。

    3.2.3 运行结果

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

    考验做题者对栈的灵活运用

  • 相关阅读:
    LeetCode 382. Linked List Random Node
    LeetCode 398. Random Pick Index
    LeetCode 1002. Find Common Characters
    LeetCode 498. Diagonal Traverse
    LeetCode 825. Friends Of Appropriate Ages
    LeetCode 824. Goat Latin
    LeetCode 896. Monotonic Array
    LeetCode 987. Vertical Order Traversal of a Binary Tree
    LeetCode 689. Maximum Sum of 3 Non-Overlapping Subarrays
    LeetCode 636. Exclusive Time of Functions
  • 原文地址:https://www.cnblogs.com/whb1/p/12546143.html
Copyright © 2011-2022 走看看