目录
3.3 栈的表示和操作的实现
3.3.1 栈的抽象数据类型的类型定义
ADT Stack{
数据对象:
D = { ai|ai ∈ ElemSet, i=1,2,...,n, n≥0}
数据关系:
R1 = { <ai-1, ai >| ai-1, ai∈D, i=2,...,n}
约定an端为栈顶,a1端为栈底。
基本操作:初始化、进栈、出栈、取栈顶元素等
}ADT Stack
InitStack(&s) 初始化操作
操作结果:构造一个空栈S。
DestoryStack(&S) 销毁栈操作
初始条件:栈S已存在。
操作结果:栈S被销毁。
StackEmpty(S) 判定S是否为空栈
初始条件:栈S已存在
操作结果:若栈S为空栈,则返回TRUE,
否则FALSE。
StackLength(S) 求栈的长度
初始条件:栈S已存在。
操作结果:返回S的元素个数,即栈的长度。
GetTop(S, &e) 取栈顶元素
初始条件:栈S已存在。
操作结果:用e返回S的栈顶元素。
ClearStack(&S) 栈置空操作
初始条件:栈S已存在。
操作结果:将S清为空栈。
Push(&S, e) 入栈操作
初始条件:栈S已存在。
操作结果:插入元素e为新的栈顶元素。
Pop(&S, &e) 出栈操作
初始条件:栈S已存在。
操作结果:删除S的栈顶元素an,并用e返回其值。
3.3.2 顺序栈的表示和实现
1. 示范
2. 栈满时的处理方法
1、报错,返回操作系统。
2、分配更大的空间,作为栈的存储空间,将原栈的内容移入新栈。
3. 数组作为顺序栈存储方式
4. 顺序栈的表示
# define MAXSIZE 100
typedef struct{
SElemType *base; // 栈底指针
SElemType *top; // 栈顶指针
int stacksize; // 栈可用最大容量
}SqStack;
注:top和base可以定义为int,用来放下标,要相减必须指向同一数组。
顺序栈算法基本操作:
1. 顺序栈的初始化
Status InitStack(SqStack &S){ // 构造一个空栈
S.base = new SElemType[MAXSIZE]; // c++语法中new后面跟类型, 或
// S.base = (SElemType*)malloc(MAXSIZE*sizeof(SElemType)); // c语法
// 分配MAXSIZE空间的SElemType类型,malloc:动态分配函数,转换成SElemType类型指针
if (!S.base)
exit(OVERFLOW); // 存储分配失败
S.top = S.base; // 栈顶指针等于栈底指针
S.stacksize = MAXSIZE;
return OK;
}
2. 顺序栈判断栈是否为空
Status StackEmpty(SqStack S){
// 若栈为空,返回TRUE;否则返回FALSE
if(S.top == S.base)
return TRUE;
else
return FALSE;
}
3. 求顺序栈长度
int StackLength( SqStack S )
{
return S.top-S.base;
}
4. 清空顺序栈
Status ClearStack( SqStack S ){
if( S.base ) // 如果这个栈存在
S.top = S.base;
return OK;
}
5. 销毁顺序栈
Status DestoryStack( SqStack &S){
if( S.base )
{
delete S.base;
S.stacksize = 0;
S.base = S.top = NULL;
}
return OK;
}
6. 顺序栈的入栈
(1)判断是否栈满,若满则出错(上溢)
(2)元素e压入栈顶
(3) 栈顶指针加1
Status Push( SqStack &S, SElemType e){
if( S.top-S.base == S.stacksize ) // 栈满
return ERROR;
*S.top ++= e; // *S.top=e; S.top++;
return OK;
}
7. 顺序栈的出栈
(1)判断是否栈空,若空则出错(下溢)
(2)获取栈顶元素e
(3)栈顶指针减1
Status Pop(SaStack &S, SElemType &e){
// 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR
if(S.top == S.base) // 等价于 if(StackEmpty(S))
return ERROR;
e = *--S.top; // --S.top; e=*S.top;
return OK;
}
3.3.3 链栈的表示和实现
1. 链栈的表示
链栈是运算受限的单链表,只能在链表头部进行操作。
typedef struct StackNode{
SElemType data;
struct StackNode *next;
} StackNode, *LinkStack;
LinkStack S;
2. 链栈的初始化
void InitStack(LinkStack &S){
// 构造一个空栈,栈顶指针置为空
S = NULL;
return OK;
}
3. 判断链栈是否为空
Status StackEmpty(LinkStack S){
if (S==NULL)
return ERROR;
else
return FALSE;
}
4. 链栈的入栈
加一p指针,给p的next域赋给头结点s地址,在将s存入p的地址,再将值赋给s。
Status Push(LinkStack &S, SElemType e){
p = new StackNode; // 生成新结点p
p -> data = e; // 将新结点数据域置为e
p -> next = S; // 将新结点插入栈顶
S = p; // 修改栈顶指针
return OK;
}
5. 链栈的出栈
用新的元素e和指针p提取元素和指针,头结点指向next域的结点,释放p。
Status Pop(LinkStack &S, SElemType &e){
if(S==NULL)
return ERROR;
e = S -> data;
p = S;
S = S -> next;
delete p;
return OK;
}
6. 取栈顶元素
SElemType GetTop(LinkStack S){
if(S!=NULL)
return S->data;
}
3.4 栈与递归
3.4.1 递归的定义
(1)若一个对象部分地包含它自己,或用它自己给自己定义,则称这个对象是递归的;
(2)若一个过程直接地或间接地调用自己,则称这个过程是递归的过程。
e.g. 递归求n的阶乘
long Fact( long n ){
if( n == 0 )
return 1;
else
return n * Fact(n-1);
}
(1)
(2)
(3)
3.4.2 递归问题——用分治法求解
3.4.3 递归优缺点
(1)
(2)