1.栈
1.1
栈是一种特殊的线性表。其特殊性在于限定插入和删除数据元素的操作只能在线性表的一端进行。如下所示:
结论:后进先出(Last In First Out),简称为LIFO线性表。
栈的基本运算有六种:
构造空栈:InitStack(S)、
判栈空: StackEmpty(S)、
判栈满:
进栈:
退栈:
取栈顶元素:StackTop(S),不同与弹出,只是使用栈顶元素的值,该元素仍在栈顶不会改变。
我们要了解的是,在顺序栈中有"上溢"和"下溢"的概念。顺序栈好比一个盒子,我们在里头放了一叠书,当我们要用书的话只能从第一本开始拿(你会把盒子翻过来吗?真聪明^^),那么当我们把书本放到这个栈中超过盒子的顶部时就放不下了(叠上去的不算,哼哼),这时就是"上溢","上溢"也就是栈顶指针指出栈的外面,显然是出错了。反之,当栈中已没有书时,我们再去拿,看看没书,把盒子拎起来看看盒底,还是没有,这就是"下溢"。"下溢"本身可以表示栈为空栈,因此可以用它来作为控制转移的条件。
链栈则没有上溢的限制,它就象是一条一头固定的链子,可以在活动的一头自由地增加链环(结点)而不会溢出,链栈不需要在头部附加头结点,因为栈都是在头部进行操作的,如果加了头结点,等于要在头结点之后的结点进行操作,反而使算法更复杂,所以只要有链表的头指针就可以了。
1.2 栈的顺序存储
使用c++的面向对象封装:
- //
Test.cpp : Defines the entry point for the console application. - //
- #include
"stdafx.h" - #include
- using
namespace std; - #define
MAX 10 // MAXIMUM STACK CONTENT - class
stack - {
- private:
-
int arr[MAX]; -
int top; - public:
-
stack() -
{ -
inItStack(); -
} -
-
-
-
void inItStack() -
{ -
top=-1; -
} -
-
-
-
void push(int a) -
{ -
top++; -
if(top < MAX) { -
arr[top]=a; -
} else { -
cout<<"STACK FULL!!"<<top; -
} -
} -
-
-
-
int pop() -
{ -
if(isEmpty()) { -
cout<<"STACK IS EMPTY "; -
return NULL; -
} else { -
int data=arr[top]; -
arr[top]=NULL; -
top--; -
return data; -
} -
} -
-
-
-
-
bool isEmpty() -
{ -
if(top == -1) return true; -
else return false; -
} - };
- int
main() - {
-
stack a; -
a.push(3); -
a.push(10); -
a.push(1); -
cout<<"Pop:"<<a.pop(); -
return 0; - }
1.3 栈的链式存储
若是栈中元素的数目变化范围较大或不清楚栈元素的数目,就应该考虑使用链式存储结构。人们将用链式存储结构表示的栈称作"链栈"。链栈通常用一个无头结点的单链表表示。如图所示:
栈的操作是线性表操作的特例。
简单用c实现:
- //
Test.cpp : Defines the entry point for the console application. - //
- #include
"stdafx.h" - #include
- #include
"stdlib.h" - #include
- using
namespace std; - //宏定义
- #define
TRUE 1 - #define
FALSE 0 - #define
OK 1 - #define
ERROR 0 - #define
INFEASIBLE -1 - #define
OVERFLOW -2 - #define
STACKEMPTY -3 -
- #define
LT(a,b) ((a)<(b)) - #define
N = 100 -
- typedef
int Status; - typedef
int ElemType; -
- typedef
struct LNode{ -
ElemType data; -
struct LNode *next; - }LNode,
*LinkList; -
- typedef
struct stack{ -
LinkList top; - }
STACK; -
-
-
-
-
- void
InitStack(STACK &S); - void
Push(STACK &S,ElemType e); - void
Pop(STACK &S, ElemType *e); - ElemType
GetTop(STACK S,ElemType *e); - int
StackEmpty(STACK S); -
-
-
-
- void
InitStack(STACK &S) - {
-
S.top=NULL; - }
-
-
-
-
- void
Push(STACK &S,ElemType e) - {
-
LinkList p; -
p = (LinkList )malloc(sizeof(LNode)); -
if (!p) exit(OVERFLOW); -
p->data = e; -
p->next = S.top; -
S.top = p; - }
-
-
-
- void
Pop(STACK &S, ElemType *e) - {
-
LinkList p; -
if(StackEmpty(S)) exit(STACKEMPTY); -
*e = S.top->data; -
p = S.top; -
S.top = p->next; -
free(p); - }
-
-
-
- ElemType
GetTop(STACK S, ElemType *e) - {
-
if(StackEmpty(S)) exit(STACKEMPTY); -
*e = S.top->data; - }
-
-
-
-
- int
StackEmpty(STACK S) - {
-
if(S.top==NULL) return TRUE; -
return FALSE; - }
-
- void
main() - {
-
-
STACK S; -
InitStack( S); -
Push(S, 3); -
Push(S, 4); -
ElemType e; -
Pop(S,&e); -
cout<<"Pop elem:"<<e; - }
1.4 栈的应用
1)
2)语法词法分析
3)表达式求值等
1.5 栈的递归和实现
汉诺塔的问题:
解决:
1)如果有一个盘子,直接从X移到Z即可。
2)如果有n个盘子要从X移到Z,Y作为辅助。问题可以转化为,先将上面n-1个从X移动到Y,Z作为辅助,然后将第n个从X移动到Z,最后将剩余的n-1个从Y移动到Z,X作为辅助。
完整实现代码,包括栈的实现:
- //
Test.cpp : Defines the entry point for the console application. - //
- #include
"stdafx.h" - #include
- #include
"stdlib.h" - #include
- using
namespace std; - //宏定义
- #define
TRUE 1 - #define
FALSE 0 - #define
OK 1 - #define
ERROR 0 - #define
INFEASIBLE -1 - #define
OVERFLOW -2 - #define
STACKEMPTY -3 -
- #define
LT(a,b) ((a)<(b)) - #define
N = 100 -
- typedef
int Status; - typedef
int ElemType; -
- typedef
struct LNode{ -
ElemType data; -
struct LNode *next; - }LNode,
*LinkList; -
- typedef
struct stack{ -
LinkList top; - }
STACK; -
-
-
-
-
- void
InitStack(STACK &S); - void
Push(STACK &S,ElemType e); - void
Pop(STACK &S, ElemType *e); - ElemType
GetTop(STACK S,ElemType *e); - int
StackEmpty(STACK S); -
-
-
-
- void
InitStack(STACK &S) - {
-
S.top=NULL; - }
-
-
-
-
- void
Push(STACK &S,ElemType e) - {
-
LinkList p; -
p = (LinkList )malloc(sizeof(LNode)); -
if (!p) exit(OVERFLOW); -
p->data = e; -
p->next = S.top; -
S.top = p; - }
-
-
-
- void
Pop(STACK &S, ElemType *e) - {
-
LinkList p; -
if(StackEmpty(S)) exit(STACKEMPTY); -
*e = S.top->data; -
p = S.top; -
S.top = p->next; -
free(p); - }
-
-
-
- ElemType
GetTop(STACK S, ElemType *e) - {
-
if(StackEmpty(S)) exit(STACKEMPTY); -
*e = S.top->data; - }
- void
printStack(STACK S){ -
LinkList p; -
p = S.top; -
printf("栈: "); -
while (p) { -
printf("%d ", p->data); -
p = p->next; -
} - }
-
-
-
-
- void
move(STACK &Sa,STACK &Sb) - {
-
ElemType e; -
Pop(Sa,&e); -
Push(Sb, e); - }
- void
hanoi(int n,STACK &X,STACK &Y,STACK &Z) - {
-
if(n==1) return move(X, Z); //将圆盘1号直接移到z -
hanoi(n-1,X,Z,Y); //将x上的1大n-1圆盘移到y,z做辅助塔 -
move(X, Z); //将编号为n的圆盘移z -
hanoi(n-1,Y,X,Z); //将y上的1大n-1圆盘移到z,x做辅助塔 - }
-
-
-
-
- int
StackEmpty(STACK S) - {
-
if(S.top==NULL) return TRUE; -
return FALSE; - }
-
- void
main() - {
-
-
STACK Sx, Sy,Sz; -
InitStack( Sx); -
InitStack( Sy); -
InitStack( Sz); -
int i, n = 10; -
for (i = 10 ; i>=1 ;i--) { -
Push(Sx, i); -
} -
printStack(Sx); -
hanoi(n, Sx,Sy,Sz); -
printStack(Sz); - }