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

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

0.PTA得分截图

1.本周学习总结

1.1 栈

  • 顺序栈:用一段连续的存储空间来存储栈中的数据元素,比较常见的是用数组来实现顺序栈

栈的声明

typedef struct sta
 {
     int *top;            /* 栈顶指针 */
     int *bottom;        /* 栈底指针 */
     int stack_size;        /* 栈的最大容量 */
 }stack;

栈的初始化

  stack InitStack (stack p)
  {
      p.bottom = (int *)malloc(p.stack_size * sizeof(int));
      if (p.bottom == NULL)
      {
          printf("初始化栈失败\n");
          exit(0);
      }
     p.top = p.bottom;
     p.stack_size = MAX_SIZE;
 
     return p;
 }

入栈

stack Push (stack p)
  {
      int data;
      if (StackFull(p) == Full)
      {
          printf("栈空间已满,无法入栈");
          return p;
      }
     printf("Please input data");
     scanf("%d", &data);
     *p.top = data;
     p.top++;
 
     return p;
  }

出栈

stack Pop (stack p)
 {
     if (StackEmpty(p) == Empty)
     {
         printf("栈为空栈,无法出栈 ");
         return p;
     }
     p.top--;
     printf("出栈元素为:%d\n", *p.top);
 
     return p;
 }

判断栈是否为空

int StackEmpty (stack p)
 {
     if (p.top == p.bottom)
     {
         return Empty;
     }
     else
     {
         return Avail;
     }
 }

判断栈是否为满

int StackFull (stack p)
 {
     if (p.top - p.bottom == p.stack_size)
     {
         return Full;
     }
     else
     {
         return Avail;
     }
 }

遍历栈中的元素

void DisplyStack (stack p)
 {
     if (StackEmpty(p) == Empty)
     {
         printf("栈为空栈,无法遍历\n");
         return;
     }
     printf("栈中元素为:");
     printf("顶端[");
     while (p.top != p.bottom)
     {
         p.top--;
         printf("%d-", *p.top);
     }
     printf("]底端\n");
 }
  • 链栈:链式栈中的元素以Node的形式存储,节点Node中存有此节点存于栈中的元素以及指向下个节点的指针

栈的声明

typedef struct node 
{
	SElemType  data;//数据域
	struct node *next;//指针域
}LinkStackNode;

入栈

Status Push(LinkStackNode *top, SElemType x) 
{
	LinkStackNode * p;
	p = (LinkStackNode *)malloc(sizeof(LinkStackNode));
	if (!p)  return ERROR;    
	p->data = x;
	p->next = top->next;
	top->next = p;    
	return OK;
}

出栈

Status Pop(LinkStackNode *top, SElemType *x)
{  
	LinkStackNode * p;
	p = top->next;
	if (p == NULL)   
		return OVERFLOW;
	top->next = p->next;
	*x = p->data;
	free(p);    
	return OK;
}

1.2 栈的应用

  • 数制转换

十进制数N和其他d进制数的转换是计算机实现计算的基本问题,其解决方法很多,同样用栈也可以解决
下述算法实现了十进制数转八进制数,并打印结果

public class Conversion 
{
    public static void conversion(int N) 
    {
        ArrayStack<Integer> stack = new ArrayStack<>();
        while (N != 0) 
        {
            stack.push(N % 8);
            N /= 8;
        }
        while (!stack.isEmpty()) 
        {
            System.out.print(stack.pop());
        }
    }

    public static void main(String[] args) 
    {
        conversion(2007);
    }
}

  • 括号匹配检验

假设表达式中包含三种括号:圆括号、方括号和花括号,并且它们可以任意嵌套。例如{()[{}]}或[{()}([])]等为正确格式,而{[}()]或[({)]为不正确的格式。
于是我们可以设计算法:算法需要一个栈,在读入字符的过程中,如果是左括号,则直接入栈,等待相匹配的同类右括号;如果是右括号,且与当前栈顶左括号匹配,则将栈顶左括号出栈,如果不匹配则属于不合法的情况。另外,如果碰到一个右括号,而堆栈为空,说明没有左括号与之匹配,则非法。那么,当字符读完的时候,如果是表达式合法,栈应该是空的,如果栈非空,那么则说明存在左括号没有相应的右括号与之匹配,也是非法的情况。
下述算法实现了对该表达式的括号匹配检验

public class Match 
{
    public static boolean match(String s) 
    {
        ArrayStack<Character> stack = new ArrayStack<>();
        for (int i = 0; i < s.length(); i++) 
        {
            char c = s.charAt(i);
            switch (c) 
            {
            case ')':
                if (!stack.isEmpty() && stack.pop() == '(') 
                {
                    break;
                }
                else 
                {
                    return false;
                }
            case ']':
                if (!stack.isEmpty() && stack.pop() == '[')
                {
                    break;
                }
                else 
                {
                    return false;
                }
            case '}':
                if (!stack.isEmpty() && stack.pop() == '{') 
                {
                    break;
                }
                else 
                {
                    return false;
                }
            default:
                stack.push(c);
                break;
            }
        }
        return stack.isEmpty();
    }

    public static void main(String[] args)  
    {
        System.out.println(match("{[()]()[{}]}"));
        System.out.println(match("{[()]}}"));
    }
}
  • 迷宫求解

求迷宫从入口到出口的所有路径是一个经典的程序设计问题。由于计算机解迷宫时,通常用的是“穷举求解”的方法,即从入口出发,顺某一方向向前探索,若能走通,则继续往前走;否则沿原路退回,换一个方向再继续探索,直至所有可能的通路都探索到为止。
为了保证在任何位置都能沿原路退回,显然需要用一个后进先出的结构来保存从入口到当前位置的路径。因此在迷宫求解时应用“栈”也就是自然而然的事情了。
在计算机中,我们可以用一个二维数组来表示一个迷宫
求解迷宫的算法思想的伪代码

初始化,将起点加入堆栈;
while(堆栈不为空)
{
    取出栈顶位置为当前位置;
    如果 当前位置是终点,
    则 使用堆栈记录的路径标记从起点至终点的路径;
    否则
    {
        按照从下、右、上、左的顺序将当前位置下一个可以探索的位置入栈;
        如果 当前位置的四周均不通
        则 当前位置出栈;
    }
}

1.3 队列

  • 顺序队列:队列的这种头尾相接的顺序存储结构称为循环队列。

队列声明

#define MAXSIZE  5    //最大容量是5个元素
struct queue   //队列

{
       int a[MAXSIZE];   //队列元素
       int front;          //队头
       int rear;           //队尾
};

判断循环队列是否为空

int SeQueue::Empty()
{ 
if(rear==front) return(1);
else return(0);
}

在循环队列中插入新的元素x

void SeQueue::AddQ(ElemType x)
{
	if ((rear + 1) % MAXSIZE == front)
		cout << " QUEUE IS FULL! " << endl;
	else
	{
		rear = (rear + 1) % MAXSIZE;
		elem[rear] = x;
		cout << " OK!";
	}
}

删除队列中队首元素

ElemType SeQueue::DelQ()
{
	if (front == rear)
	{
		cout << " QUEUE IS EMPTY! " << endl; return -1;
	}
	else 
	{
		front = (front + 1) % MAXSIZE;
		return(elem[front]);
	}
}

取队列中的队首元素

ElemType SeQueue::Front()
{
	ElemType x;
	if (front == rear)
		cout << "QUEUE IS EMPTY " << endl;
	else 
		x = elem[(front + 1) % MAXSIZE];
	return (x);
}
  • 环形队列:

队列声明

typedef struct
{
	ElemType data[Max]; 
	int front;   
	int count;   
}QueueType;

初始化队列

void InitQueue(QueueType *&q)
{
	q = (QueueType *)malloc(sizeof(QueueType));
	q->front =0;
	q->count =0;
}

判断队列是否为空

void  EmptyQueue(QueueType *q)
{
	if (q->count==0)
		cout<< "队列为空!" << endl;
	else
		cout << "队列不为空!" << endl;
}

元素进队

int enQueue(QueueType*& q, ElemType x)
{
	int rear;
	if (q->count == Max) //队满溢出
		return 0;
	else
	{
		rear = (q->front + q->count) % Max;
		rear = (rear + 1) % Max;
		q->data[rear] = x;
		q->count++;
		return 1;
	}
}

元素出队

int deQueue(QueueType *&q,ElemType &x)
{
	if(q->count==0)
		return 0;
	else
	{
		q->front=(q->front+1)%Max;
		x=q->data[q->front];
		q->count--; 
	}
}

输出队列的元素个数

void LenghtQueue(QueueType *q)
{
	cout << q->count << endl;
}

释放队列

void DestroyQueue(QueueType *q)
{
	free(q);
}
  • 链队列:

队列声明

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* enElem = (QNode*)malloc(sizeof(QNode));
    enElem->data = data;
    enElem->next = NULL;
    rear->next = enElem;
    rear = enElem;
    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);
}
  • 队列应用

2.PTA实验作业

  • 代码上传码云没整明白,所以还是截图代码了,下次一定整明白

2.1 符号配对

2.1.1 解题思路及伪代码

解题思路:把比较特殊的//用< >代替,创建一个栈然后把找到的对应符号放入栈中,然后进行比较得到符号是否匹配

int main
{
  static char ch1[1000], ch2[1000], ch[10000];//ch放代码,ch2放找到的符号,ch1用于符号匹配
for(i = 0;; i++)
  {
    找到对应符号然后放入ch2中//用<>代替两个的符号
  }
int flag=1 用于记录
for (i = 0; i < k; i++)
  {
    if ch2中符号是左符号,放入栈中
    else if ch2中符号是右符号
    {
      if 栈中存在符号,并且和ch2和栈中符号匹配,则消除栈中该符号
      else 输出NO 和对应缺少的符号,flag=0
    }
  }
if flag=1同时栈中无符号 输出YES
else
  {  输出  NO
     根据栈中情况输出对应缺少符号
  }
}

2.1.2 总结解题所用的知识点

栈的出栈和入栈,栈指针的变化来判断栈中元素变化

2.2 银行业务队列简单模拟

2.2.1 解题思路及伪代码

解题思路:依题意得A总比B先输出,且当A中含有元素时总先输出两个,所以按照2:1的比例输出AB中的数,用队列来表示就是出队操作

int main
{
struct queue QA, QB;//创建两个队列
Createqueue(&QA);
Createqueue(&QB);

scanf("%d", &n);
for (i = 0; i < n; i++)
{
  if是奇数 放入队列QA  
  else 放入队列QB
}
while 两个队列不同时为空
{
  if QA不为空 输出QA中的数,同时出队
  if QA不为空 输出QA中的数,同时出队
  if QB不为空 输出QB中的数,同时出队
}

2.2.2 总结解题所用的知识点

队列的出队和入队

3.阅读代码

3.1 题目及解题代码

解题代码

class Solution:
    def validateStackSequences(self, pushed: List[int], popped: List[int]) -> bool:
        stack, i = [], 0
        for num in pushed:
            stack.append(num) # num 入栈
            while stack and stack[-1] == popped[i]: # 循环判断与出栈
                stack.pop()
                i += 1
        return not stack

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


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

由于题目规定 栈的所有数字均不相等 ,因此在循环入栈中,每个元素出栈的位置的可能性是唯一的(若有重复数字,则具有多个可出栈的位置)。因而,在遇到 “栈顶元素 == 弹出序列的当前元素” 就应立即执行出栈。
先找到进栈中最后一个(我叫做标准值),在出栈之后的的所有元素,都只会在这个值后面。所以在出栈数列中最后一个进栈的数字后面一定是递减的。可以来排个序。对于这个标准值前面的数字呢?如果说前一个数字比后一个数字小没什么关系,但是如果说前面数字比后面数字大就要讨论一下了。
就拿[0,1,2,3,4,5,..,12]和[0,4,3,5,2,1,7,8,10,11,9,6]看这个地方有个5,比后面的2要大。我们已经看到0,3,4已经出栈了。那么现在栈呢剩下的就是[1,2]我们不能选1,中间隔着2,所以我们要选择离5更近的一个数字。后面11比9大,这个时候栈内还有[6,9]选择离11更接近的9,最后就是剩下的6。

posted @ 2021-04-05 21:40  山无垢山城  阅读(93)  评论(1编辑  收藏  举报