形状
栈是一种线性表,它遵循先出后进 ,在插入删除时**++只能在栈顶进行++**。
在程序设计中,如果按照保存数据的相反顺序来使用数据,就可以用栈实现。
顺序表示(顺序栈)
- top指针初始化完成后,指向栈底,插入一个数据便加一,删除一个数据减一。栈非空时,top一直指向栈顶元素的上一个。
- base指针初始化完成后,始终指向栈底。若其为空,则说明栈结构不存在。
c
#define MAXSIZE 100
typedef struct
{
SElemType *base;//栈底指针
SElemType *top;//栈顶指针
int stacksize;//栈可用最大容量
}SqStack;
初始化
c
Status InitStack(SqStack& S)
{
S.base = new SqStack[MAXSIZE];//用栈底地址开辟一串空间
if (!S.base)exit(OVERFLOW);
S.top = S.base;//初始化top指针
S.stacksize = MAXSIZE;//初始化大小
return ok;
}
入栈
c
Status Push(SqStack &S, SElemType e)
{//插入元素e为新的栈顶元素
if(S.top - S.base == S.stacksize) return error;//栈满
*S.top++ = e;//先使*S.top等于e,再令top指针指向下一个地址
return ok;
}
出栈
c
Status Pop(SqStack &S, SElemType& e)
{//删除栈顶元素,用e返回其值
if(S.top == S.base) return error;//栈空
e = *--S.top;//因为栈顶指针在栈非空时一直指向栈顶元素的下一个,所以要先减后取,此时栈顶指针便会减一且栈顶元素被取出
return ok;
}
取栈顶元素
c
Status GetTop(SqStack S)
{//取出栈顶元素,不修改指针
if(S.top != S.base)//栈非空
return *(S.top - 1);//不改变指针,所以直接减一即可
}
链式表示(链栈)
c
#define MAXSIZE 100
typedef struct StackNode//链栈节点
{
ElemType data;
struct StackNode *next;//指向栈顶元素
}StackNode, *LinkStack;
初始化
c
Status InitStack(LinkStack& S)
{//建立空栈S,栈顶指针置空
S = NULL;
return ok;
}
入栈
c
Status Push(LinkStack& S, SElemType e)
{//插入元素e为新的栈顶元素
StackNode p = new StackNode;
p->data = e;
p->next = S;//栈底节点保持为空,便于判断
S = p;
return ok;
}
出栈
c
Status Pop(LinkStack& S, SElemType& e)
{//删除栈顶元素,用e返回其值
if(S == NULL) return error;//栈空
e = S->data;//取出栈顶元素
StackNode p = S;//用一个新节点代替他,便于等会挪完栈顶指针后,在内存空间删除它
S = S->next;
delete p;
return ok;
}
取栈顶元素
c
Status GetTop(LinkStack S)
{//取出栈顶元素,不修改指针
if(S != NULL)//栈非空
return S->data;
}
栈与递归
c
/*
一般采用分治法
1) 把一个问题编程新问题,新问题又与原问题解法类似
2) 可以通过1转化使问题简化
3) 必须有一个明确的递归出口,或称递归边界
*/
//模板
void p(参数)
{
if(递归结束条件成立) 可直接求解;
else p(较小的参数)
}
采用递归的情况
-
定义是递归的:阶乘函数
c//e.g.阶乘函数 long Fact(long n) { if(n == 0) return 1;//0!= 1; else return n*Fact(n - 1);//较小的参数,嵌套下去计算 }
-
数据结构是递归的:链表、广义表、二叉树
c//链表的遍历,一般采用for去一个个循环,但是它符合递归(链表LNode定义中用到自己的定义去定义next) void TraverseList(LinkList p) { if(p = NULL) return; else { cout << p->data << endl; TraverseList(p->next); } } //可以简化为 void TraverseList(LinkList p) { if(p) { cout << p->data << endl; TraverseList(p->next); } }
-
问题的解法是递归的:Hanoi(汉诺)塔问题、八皇后问题、迷宫问题
Hanoi(汉诺)塔问题规则:
古代有一个焚塔,塔内有3个座A,B,C,开始时A座上有64个盘子,盘子大小不等,大的在上,小的在下,有一个老和尚想把这64个盘子从A座移到C座,但规定每次只允许移到一个盘,且在移动过程中在3个座上都始终保持大盘在下,小盘在上,在移动过程中可以利用B座。输出移动盘子的步骤。
步骤示意图(n = 3):
c/* Hanoi(汉诺)塔问题递归算法步骤: 设A柱上最初的盘子总数为n, 则当n =l时,只要将编号为1的圆盘从塔座A直接移至塔座C上即可;否则,执行以下三步: (1) 用 C 柱做过渡,将 A 柱上的(n-l)个盘子移到 B 柱上; (2) 将 A 柱上最后一个盘子直接移到 C 柱上; (3) 用 A 柱做过渡,将 B 柱上的(n-l)个盘子移到C柱上。 根据这种解法,如何将 n -1个圆盘从一个塔座移至另一个塔座的问题是一个和原问题具有相同特征属性的问题,只是问题的规模小1, 因此可以用同样的方法求解。 */ void Hanoi(int n,char A,char B,char C) { if(n == 1) move(A, 1, C);//将编号为1的圆盘从A挪到C else{ //否则开始递归 Hanoi(n-1, A, C, B); /*递归,将A上编号为1至n-l的圆盘移到B,C做辅助塔; !!!注意这里传进去的参数是不一样的,前面为参数名称,括号内为实际柱子名称 若n=3,因为Hanoi(2, A, C, B),下一层n=2函数内参数情况A(A),B(C),C(B) 若n=2,因为Hanoi(1, A, C(B), B(C)),下一层n=1函数内参数情况A(A),B(B),C(C) 若n=1,通过move(A(A), 1, C(C)),将1从A挪到C,然后返回Hanoi(2, A, C, B)执行接下去的代码 具体过程: Hanoi(3, A, B, C) ├── Hanoi(2, A, C, B) │ ├── Hanoi(1, A, B, C) │ └── Move disk 2 from A to B │ └── Hanoi(1, C, A, B) ├── Move disk 3 from A to C └── Hanoi(2, B, A, C) ├── Hanoi(1, B, C, A) └── Move disk 2 from B to C └── Hanoi(1, A, B, C) */ move(A, n, C);//直接将编号为n的圆盘从A移到C Hanoi(n-1,B,A,C);//递归,将B上编号为1至n-1的圆盘移到C,A做辅助塔 } }
在STL中的栈的主要操作函数
1.stack< > s
创建一个空栈
c
stack<栈内数据类型> s;
2. push()
将元素压入栈的顶部。
cpp
stack<int> s;
s.push(10); // 将 10 压入栈
s.push(20); // 将 20 压入栈
3. pop()
删除栈顶元素。注意,pop()
不会返回被删除的元素。
cpp
s.pop(); // 删除栈顶元素 20
4. top()
返回栈顶元素的引用,但不会删除它。
cpp
int top_element = s.top(); // 返回栈顶元素,值为 10
5. empty()
检查栈是否为空,若为空则返回 true
,否则返回 false
。
cpp
bool is_empty = s.empty(); // 检查栈是否为空
6. size()
返回栈中元素的数量。
cpp
size_t count = s.size(); // 栈中元素的数量
7. swap()
交换两个栈的内容。
cpp
stack<int> s1, s2;
s1.push(1);
s2.push(2);
s1.swap(s2); // 交换 s1 和 s2 的元素
示例代码
cpp
#include <iostream>
#include <stack>
using namespace std;
int main() {
stack<int> s;
s.push(1);
s.push(2);
s.push(3);
cout << "栈顶元素: " << s.top() << endl; // 输出 3
s.pop();
cout << "删除栈顶后,新的栈顶: " << s.top() << endl; // 输出 2
cout << "栈是否为空: " << (s.empty() ? "是" : "否") << endl;
cout << "栈的大小: " << s.size() << endl;
return 0;
}