1、2、3依次进栈,可能的出栈结果:
元素数量越多,其出栈的变化会更多
ADT stack
Data
同线性表。元素具有相同的类型,相邻元素具有前驱和后继关系。
Operation
InitStack(*S) | 初始化操作,建立一个空栈S |
---|---|
Destroy(*S) | 若栈存在,则销毁 |
ClearStack(*S) | 将栈清空 |
StackEmpty(S) | 若栈为空,则返回true,否则返回false |
GetTop(S, *e) | 若栈存在且非空,用 e 返回S的栈顶元素 |
Push(*S, e) | 若栈S存在,插入新元素e到栈S中并成为栈顶元素 |
Pop(*S, e) | 删除栈S中栈顶元素,并用e返回其值 |
StackLength(S) | 返回栈S的元素个数 |
endADT
#define OK 1
#define ERROE 0
#define MAXSIZE 100
typedef struct
{
int data[MAXSIZE];
int top;
}SqStack;
/* 时间复杂度 O(1) */
int Push(SqStack *S, int e)
{
if(S->top == MAXSIZE -1)
return ERROR;
S->data[S->top++] = e;
return OK;
}
/* 时间复杂度 O(1) */
int Pop(SqStack *S, int *e)
{
if(S->top == -1)
return ERROE;
*e = S->data[S->top];
S->top --;
return OK;
}
思路: 从数组两端向中间靠拢。top1 和 top2 是栈1 和栈2 的栈顶指针。即只要二者不相碰,则两个栈就可以一直使用。
typedef struct
{
int data[MAXSIZE];
int top1;
int top2;
}SqDoubleStack;
在入栈时需要判断给栈1还是栈2插入元素
/* 时间复杂度 O(1) */
int Push(SqDoubleStack *S, int StackNumber, int e)
{
if(S->top1 + 1 == S->top2)
return ERROR;
if(StackNumber == 1)
{
S->data[++S->top1] = e;
}
if(StackNumber == 2)
{
S->data[--S->top2] = e;
}
return OK;
}
/* 时间复杂度 O(1) */
int Pop(SqDoubleStack *S, int e, int StackNumber)
{
if(StackNumber == 1)
{
if(S->top1 == -1)
return ERROR;
*e = S->data[S->top1--];
}
if(StackNumber == 2)
{
if(S->top2 == MAXSIZE)
return ERROR;
*e = S->data[S->top2++];
}
return OK;
}
typedef struct StackNode
{
int data;
struct StackNode *next;
}StackNode, *LinkStackPtr;
typedef struct LinkStack
{
LinkStackPtr top;
int count;
}LinkStack;
/* 时间复杂度 O(1) */
int Push(LinkStack *S, int e)
{
LinkStackPtr s = (LinkStackPtr)malloc(sizeof(StackNode));
s->data = e;
s->next = S->top;
S->top = s;
S->count ++;
return OK;
}
/* 时间复杂度 O(1) */
int Pop(LinkStack *S, int *e)
{
LinkStackPtr p;
if(StackEmpty(*S)) // 判断该链表是否为空
return ERROR;
*e = S->top->data;
p = S->top; // 将栈顶结点赋给p
S->top = S->top->next; // important 栈顶指针下移
free(p);
S->count --;
return OK;
}
如果栈的使用过程中元素变化不可料,有时很小,又是非常大,则选用链栈;如果变化在可控范围内,则选用顺栈。
直接调用自己或通过一席立委的调用语句间接地调用自己的函数,称作递归函数。
每个递归定义必须有一个条件,防止陷入无穷递归
Story time
第一个月的小兔子没有繁殖能力,两个月后,开始生殖
所经过月数 1 2 3 4 5 6 7 8 9 10 11 12 兔子对数 1 1 2 3 5 8 13 21 34 55 89 144 有没有发现这个数列的规律:前两项和等于第三项
/*
* 打印前 40位 Fibonacci 数列
* 迭代法
*/
int main(void)
{
int i;
int a[40];
int a[0] = 0;
int a[1] = 1;
for(i = 2; i <= 40; i ++)
a[i] = a[i-1] + a[i-2];
for(i = 1; i <= 40; i ++)
printf("%d ", a[i]);
return 0;
/*
* 递归法
*/
int Fbi(int i)
{
if(i < 2)
return i == 0 ? 0 :1;
return Fbi(i-1)+Fbi(i-2);
}
int main(void)
{
int i;
for(i = 0; i <= 40; i ++)
printf("%d ", Fbi(i))'
return 0;
}
圆盘数 源柱 辅助柱 目标柱
void hanoi(int n, int a, int b, intc)
{
if(n > 0)
{
hanoi(n-1, a, c, b);
move(a, b);
hanoi(n-1, c, b, a);
}
}
每次走 1 级 或者 2 级,输入楼梯的阶数,求不同的走法?
解决思路:用递归将问题分解成规模更小的子问题
阶数 | 走法 |
---|---|
1 | 1 |
2 | 2 |
3 | 3 |
4 | |
n-1 | |
n-2 |
f(n) = f(n-1) + f(n-2)
边界条件:
n < 0 0 | n=1 1 | n=1 1 |
---|---|---|
n = 0 1 | n =0 1 | n=2 2 |
using namespace std;
int N;
int stairs(int n)
{
if(n < 0)
return 0;
if(n == 0)
return 1;
return stairs(n-1) + stairs(n-2);
}
int main()
{
while(cin >> N)
cout << stairs(N) << endl;
return 0;
}
9+(3-1)×3+10÷2
用后缀表达式法为: 9 3 1 - 3*+10 2 / +