参照<<大话数据结构>> 仅做学习记录
定义:栈是仅限定在表尾进行插入和删除的线性表。
先进后出,类似子弹的弹夹的子弹,对应相关操作。
允许插入和删除数据的一端叫栈顶(top),不能修改数据的地方叫栈底(bottom)
栈的插入数据叫入栈(push),删除数据叫出栈(pop)。
定义栈长度为stacksize, 栈顶的位置用top参数记录,可定义如下结构体
typedef int Element; typedef struct { Element data[stacksize]; int top; //栈顶的位置 }SqStack;
栈顶:数组的开始,下标为0处。
栈尾:数组的结尾,下标为n-1处。(n代表两个栈的元素个数之和)
- 栈1和栈2之间的数量关系
栈1------(1)空栈:top1 = -1, (2)有一个元素:top1 = 0;
栈2------(1)空栈:top2 = n; (2)有一个元素:top2 = n-1;
- 栈满
(1)top1 = n-1; top2 = n; 栈1-栈满
(2)top1 = -1; top2 = 0; 栈2-栈满
(3)top1 + 1 = top2; 栈1和栈2在中间碰上了(4-5-1第三张图),栈满。
- 根据两栈的图可定义如下的结构体
typedef int Element; typedef struct { Element data[stacksize]; int top1; //top1栈顶的位置 int top2; //top2栈顶的位置 }DoubleStack;
- 栈的push或者pop
需要传入参数:定义是操作栈1还是栈2
首先定义一个链栈LinkStack,其中的Element是链式结构体(包含数据域+指针结点)
typedef struct { Element top; // 指向栈顶结点的指针 int count; //计数 }LinkStack; typedef struct { int data; //数据域 struct StackNode *next; //指向下一个结点 }StackNode, *Element; // 由于是链式结构,需要定义一个”数据域+指针域“的结构体
对应的出栈,入栈操作:
将一串带括号的操作,去掉括号来通过栈来运算操作。
比如 9+(3-1)*3+10/2(中缀表达式) -------->表示为(后缀表达式)9 3 1 -3 * + 10 2 / +
定义:只允许一端插入(队尾)操作,另外一端进行删除(队头)操作的线性表
先进先出(FIFO),
如果定义一个队列,front定义队首的位置,rear定义队尾的位置,如下图,队列的大小为5个字节,当a5被放入了队列,rear就变成了5,但是这个时候0 1是空的。但rear却以为溢出了,这就是假溢出。为了解决假溢出于是引出了循环队列
循环队列:把队列首尾相接,这样的贵队列称为循环队列。解决了假溢出。
所以当下标为4的地方被占了,下个位置应该为0,
但这样带来了新的问题,当rear和front相等,我们不清楚此时队列是满了(4-12-7右图),还是空的(rear == front == 0),有如下两种办法解决(标志位和留空)
- 普通队列和循环队列的结构体定义
typedef Elemnt int; struct Quenen { Element val[Max]; //值 int front; // 队首 int rear; //队尾 };
链队列:其实就是正常的单链表,不过仅仅允许头部数据被删除,尾部数据被插入。
结构体:
typedef Element int; //节点 typedef struct { Element* val; Node* next; }Node; //队列链 struct Quen { Node* front; //头节点 Node* rear; //尾节点 };
应用:
线程A接收数据,利用队列tmp.push_back(); 来存储数据。
线程B利用队列tmp的先入先出的特性来消费tmp.pop();收到的数据。
问题:1.是否需要设置最大的队列容量 2.是否需要用循环队列