数据结构-2-栈与队列

数据结构-2-栈与队列

    • 栈的抽象数据类型
    • 栈的顺序存储结构
    • 栈的链式存储结构
    • 栈的应用——四则运算表达式求值
      • 后缀表达式的转换
      • 用后缀表达式求值
  • 队列
    • 队列的抽象数据类型
    • 循环顺序队列
    • 链式队列

栈(stack)是限定仅在尾表进行插入和删除操作的线性表。
允许插入和删除的一端称为栈顶(top),另一端称为栈底(buttom)。

栈的抽象数据类型

ADT 栈 (stack)
Data
	同线性表。元素具有相同的类型,相邻元素具有前驱和后继关系。
Operation
	InitStack(*S): 初始化操作,建立一个空栈S。
	DestroyStack(*S): 若栈存在,则销毁它。
	ClearStack(*S): 将栈清空。
	StackEmpty(S): 判断S是否为空栈。
	GetTop(S,*e): 若S存在且非空,用e返回S的栈顶元素。
	Push(*S,e): 插入新元素e到栈S中并成为栈顶元素。即入栈。
	Pop(*S,*e): 删除栈S中栈顶元素,并用e返回其值。即出栈。
	StackLength(S): 返回S的元素个数。
endADT

栈的顺序存储结构

结构定义:

typedef int SElemType;
typedef struct
{
	SElemType data[MAXSIZE];
	int top;		//用于栈顶指针
}SqStack;

栈的链式存储结构

结构定义:

typedef struct StackNode
{
	SElemType data;
	struct StackNode *next;
}StackNode,*LinkStackPtr;

typedef struct LinkStack
{
	LinkStackPtr top;		//top指针,count长度
	int count;
}LinkStack;

链式栈的进栈操作:

Status Push(LinkStack *S, SElemType e)
{
	LinkStackPtr s = (LinkStackPtr)malloc(sizeof(StackNode));	//创建新结点s
	s->data = e;
	s->next = S->top;		//注意s为新结点,S为链式栈,top为指针
	S->top = s;
	S->count++;
	return OK;
}

链式栈的出栈操作:

Status Pop(LinkStack *S, SElemType *e)
{
	LinkStackPtr p;
	if(StackEmpty(*S))
		return ERROR;
	*e = S->top->data;		//返回出栈的结点的值
	p = S->top;
	S->top = S->top->next;
	free(p);
	S->count--;
	return OK;
}

栈的应用——四则运算表达式求值

后缀表达式的转换

中缀表达式转换为后缀表达式的规则:(如 “9+(3-1)×3+10÷2” 转换为“9 3 1-3*+10 2/+”)
从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的一部分;若是符号,则判断其与栈顶符号的优先级,是右括号或优先级不高于栈顶符号则栈顶元素依次出栈并输出,并将当前符号进栈,一直到最终输出后缀表达式为止。
如上述例子,

  1. 9输出,+进栈。此时输出内容为:9。栈内为:+。
  2. (进栈,3输出。此时输出内容为:9 3。栈内为:+(。
  3. -进栈,1输出。此时输出内容为9 3 1。栈内为:+( -。
  4. )进栈,匹配之前的(,将栈顶依次输出。输出内容为:9 3 1-。栈内为+。
  5. *优先级大于+, 不输出进栈。3输出 。输出内容为:9 3 1-3。栈内为+ *。
  6. +优先级小于*,*输出。+优先级不大于+。 +不进栈直接输出
    输出内容为:9 3 1-3 * +。栈内为:+。
  7. 10输出,/进栈。输出内容为:9 3 1-3 * +10。栈内为:+ /。
  8. 2输出,输入内容已结束,栈顶依次输出
    输出内容:9 3 1-3 * +10 2/+。

用后缀表达式求值

后缀表达式求值的规则:
从左到右遍历表达式的每个数字和符号,遇到数字就进栈,遇到是符号,就将处于栈顶两个数字出栈,进行运算,运算结果进栈,一直到最终获得结果。
如上面的例子:

  1. 9 3 1进栈。
  2. 遇到-号,1出栈作为减数,3出栈作为被减数,得到2,2进栈。此时为9 2。
  3. 3进栈。此时为9 2 3。
  4. 遇到*号,3 2出栈,得到6,6进栈。此时为9 6。
  5. 遇到+号,6 9出栈,得到15,15进栈。此时为15。
  6. 10 2进栈。此时为15 10 2。
  7. 遇到/号,2出栈作为除数,10出栈作为被除数,得到5,5进栈。此时为15 5。
  8. 遇到+号,5 15出栈,得到20,20进栈。
  9. 后缀表达式已遍历完,20出栈并输出。

队列

队列(queue)是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。
队列是一种先进先出的线性表,允许插入的一端称为队尾,允许删除的一端称为队头。

队列的抽象数据类型

ADT 队列(Queue)
Data
	同线性表。元素具有相同的类型,相邻元素具有前驱和后继关系。
Operation
	InitQueue(*Q):初始化操作,建立一个空队列Q。
	DestroyQueue(*Q):若队列Q存在,则销毁它。
	ClearQueue(*Q)
	QueueEmpty(Q)
	GetHead(Q,*e):用e返回队列Q的队头元素。
	EnQueue(*Q,e):插入新元素e到队列Q中并成为队尾元素。
	DeQueue(*Q,*e):删除队列Q中队头元素,并用e返回其值。
	QueueLength(Q):返回队列Q的元素个数。
endADT

front指针指向队头元素,rear指针指向队尾元素的下一个位置。

循环顺序队列

循环队列的顺序存储结构:

typedef int QElemType;
typedef struct
{
	QElemType data[MAXSIZE];
	int front;
	int rear;
}SqQueue;

两种方法来判断队列是空还是满:

  1. 当front == rear且flag == 0时,队列为空;当front == rear且flag == 1时队列为满。
  2. 当front == rear时,队列为空;当只剩一个元素空间时,队列为满,即最后一个空闲单元不使用。

重点为第二种方法,判断条件为:

(rear-front+QueueSize)%QueueSize == front;

链式队列

链队列的存储结构:

typedef int QElemType;
typedef struct QNode
{
	QElemType data;
	struct QNode *next;
}QNode,*QueuePtr;

typedef struct
{
	QueuePtr front,rear;
}LinkQueue;

你可能感兴趣的:(数据结构)