一、考试内容:
1,栈的定义,逻辑结构和常用运算;
特点:后进先出,先进后出
栈(Stack):是限定只在表尾进行插入和删除操作的线性表。
栈顶(top):表尾端,进行插入和删除操作的一端。
栈底(bottom):表头一端,即不进行操作的一端。
空栈:不含任何元素的栈。
常用运算:
ADT Stack {
数据对象:
数据关系: 约定an端为栈顶,a1端为栈底。
基本操作:
InitStack(&S)操作结果:构造一个空栈S
DestroyStack(&S) 初始条件:栈S已经存在。 操作结果:栈S被销毁。
ClearStack(&S) 初始条件:栈S已经存在。 操作结果:将S清为空栈。
StackEmpty(S) 初始条件:栈S已经存在。 操作结果:若栈S为空栈,在返回true,否则返回false。
StackLength(S) 初始条件:栈S已经存在。 操作结果:返回S的元素个数,即栈的长度。
GetTop(S,&e) 初始条件:栈S已经存在且非空。
操作结果:用e返回S的栈顶元素(栈顶元素不删除,top指针不改变) 。
Push(&S,e) 初始条件:栈S已经存在。 操作结果:插入元素e为新的栈顶元素。
Pop(&S,&e) 初始条件:栈S已经存在且非空。操作结果:删除S的栈顶元素,并用e返回其值。
StackTraverse(S,visit())初始条件:栈S已经存在且非空。
操作结果:从栈底到栈顶依次对S的每个数据元素调用函数visit()。一旦visit()失败,则操作失败。
} ADT Stack
2,栈的存储结构
两种:顺序存储结构和链表存储结构。
顺序栈:栈的顺序存储结构,利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素;同时附设指针top指向栈顶元素在顺序栈中的位置。
#define STACK_INIT_SIZE 100 //存储空间初始分配量
#define STACKINCREMENT 10 //存储空间分配增量
typedef struct {
SElemType *base;
//在栈构造之前和销毁之后,base的值为NULL
SElemType *top; //栈顶指针
int stacksize;
//当前已分配的存储空间,以元素为单位。
} SqStack
初值指向栈底,即top==base可作为栈空的标记; 每当插入新的栈顶元素时,指针top增1;
删除栈顶元素时,指针top减1,因此,非空栈中的栈顶指针始终在栈顶元素的下一个位置上。
顺序栈基本运算:
初始化:
InitStack S.base=(SElemType *)malloc(STACK_INIT_SIZE *sizeof(SElemType));//分配栈的存储区、赋基址
if (!S.base) exit (OVERFLOW); //存储分配失败
S.top=S.base; //栈顶指针初值
S.stacksize=STACK_INIT_SIZE; //栈大小初值
入栈:
Push S.base=(SElemType*)realloc(S.base, (S.stacksize+STACKINCREMENT)*sizeof(SElemType));//栈满处理
S.top=S.base+S.stacksize; //能与下一句互调吗?
S.stacksize+=STACKINCREMENT;
出栈:Pop e=*--S.top;//含义?
取栈顶元素: GetTop e=*(S.top-1); //含义?
栈的链式存储结构:链式栈
*链式栈无栈满问题,空间可扩充
*插入与删除仅在栈顶处执行
*链式栈的栈顶在链头 //无表头结点的单链表
typedef struct node {
sElemtype data; //结点
struct node *next; //链指针
} StackNode;
typedef struct {
StackNode *top; //栈顶指针
} LinkStack;
入栈:
p->data = x;
p->next = S->top; //前插
S->top = p;
取栈顶: x = S->top->data;
出栈:
p = S->top;
S->top = p->next;
x = p->data;
free (p);
3,栈的实际应用;
数制转换;括弧匹配的检验;行编辑程序;表达式求值;递归
4,栈与递归的关系;
递归定义:若一个对象部分地包含它自己, 或用它自己给自己定义, 则称这个对象是递归的;
递归的三种情况: 定义是递归的(函数);数据结构是递归的(二叉树、广义表);问题的解法是递归的;(hanoi塔)
递归时要实现的规则是:“后调用先返回”,此时的内存管理实行“栈式管理”。
栈式管理: 系统将整个程序运行时所需的数据空间安排在一个栈中,每当调用一个函数时,就为函数中使用的参数、局部变量等在栈顶分配一个存储区,每当从一个函数退出时,就释放它的存储区,从栈顶将其删除,则当前正运行的函数的数据区必在栈顶。为了保证递归函数正确执行,系统需设立一个“递归工作栈”,作为整个递归函数运行期间使用的数据存储区。 这个栈同样可以是顺序栈也可以是链式栈。
5,队列的定义及存储结构;
定义:只允许在表的一端进行插入,而在另一端删除元素的线性表。 特点:先进先出、后进后出
队尾(rear):在队列中,允许插入的一端叫队尾。 队头(front):允许删除的一端称为队头。
顺序存储结构:
用一组地址连续的存储单元依次存放从队列头到队列尾的元素。
指针:front:指示队头元素的位置 ;rear:指示队尾元素的位置。
初始化建空队列时,令front=rear=0
插入新的队尾元素,尾指针增1,rear = rear + 1
删除队头元素,头指针增1, front = front + 1
非空队列中:
头指针始终指向队列头元素,
尾指针始终指向队列尾元素的下一个位置。
循环队列:解决假溢出问题。
等式q.rear=q.front无法判别队列空间是“空”还是“满”。为了区分队空和队满:
①另设一个标志位以区别队列是“空”还是“满”; ②少用一个元素空间,约定以“队列头指针在队列尾指针的下一位置上”作为队列呈现“满”状态的标志。通过求模运算来实现指针的变化。
队满条件:(rear+1) % maxsize == front; 队空条件:front == rear; 队列初始化:front = rear = 0;
队头指针进1:入队 front = (front+1) %maxsize; 队尾指针进1: 出队 rear = (rear+1) % maxsize;
求队长:(rear-front+maxsize)%maxsize
循环队列的类型定义
#define MAXQSIZE 100 //队列最大长度
typedef struct {
QElemType *base; //初始化的动态分配存储空间
int front; //头指针,若队列不空,指向队列头元素
int rear; //尾指针,若队列不空,指向队列尾元素的下一个位置。
} SqQueue;
链队列:队列的链式表示
链队列中,有两个分别指示队头和队尾的指针。队头指针指向头结点,队列尾的指针指示队尾。
无队满问题,但有队空问题。空的链队列的判决条件队头指针和队尾指针均指向头结点
链式队列的定义(单链队列)
typedef struct QNode {
QElemType data;
Struct QNode *next;
}QNode,*QueuePtr;
typedef struct {
QueuePtr front; //队头指针
QueuePtr rear; //队尾指针
}LinkQueue;
初始化: Q.front→next=null;
入队: Q.rear→next=p; //队尾最后一个元素和其连上
Q.rear=p; //修改队尾指针
出队: p=Q.front→next; e=p→data; //获得待删结点
Q.front→next=p→next; //不修改队头指针,修改头结点的指针
6,队列的应用。
OS中:1)解决计算机主机与外设不匹配的问题;2)解决由于多用户引起的资源竞争问题;
3)离散事件的模拟----模拟实际应用中的各种排队现象; 4)用于处理程序中具有先进先出特征的过程;
二、考试要求:
了解栈和队列的逻辑结构定义,
栈和队列是操作受限的线性表。只能在表的首尾部两端进行数学运行。
栈:只能在表尾进行插入、删除;队列:在表尾插入,表头删除。
掌握栈和队列运算特点,掌握栈和递归的关系,(简答)
掌握栈和队列的顺序存储结构。
在算法实现方面要求,可以熟练利用栈和队列的顺序存储结构解决实际的问题,如:走迷宫问题、表达式括号匹配问题等。