栈
特点:
1.先进后出
2.分为顺序栈和链栈
3.对于链栈来说
使用头插头删法:(建议使用这种方式)
栈顶就是头结点,没有栈底(NULL)
使用尾插尾删法:
栈底就是头结点,栈顶:重新定义一个指针指向最后一个结点
删除得从头结点开始找到当前栈顶的前驱结点O(n)
顺序栈的结构设计
typedef struct Stack
{
ElemType *elem; //栈空间的首地址或栈底指针
int top;//下标,栈顶指针
int stacksize;//当前栈空间的大小
}SqStack,*PStack;
其他参数
#define STACK_ININ_SIZE 10 //栈空间初始大小
#define STACKINCREMENT 5 //栈空间增量
typedef int ElemType;
顺序栈操作
初始化
void InitStack(PStack st)
{
assert(st != NULL);
if(st == NULL)
{
printf("InitStack : : 栈无效\n");
exit(0);
}
st->elem = (ElemType*)malloc(STACK_ININ_SIZE * sizeof(ElemType));
if(st->elem == NULL)
{
printf("InitStack : : 空间申请失败!\n");
exit(0);
}
st->top = 0;
st->stacksize = STACK_ININ_SIZE;
}
判满
int IsEmpty(PStack st)
{
assert(st != NULL);
if(st == NULL)
{
printf("IsEmpty: : 栈无效\n");
exit(0);
}
return st->top == 0;
}
扩容
static void AppendStack(PStack st)
{
if(st->stacksize == 0)
{
InitStack(st);
return;
}
ElemType *s = (ElemType *)malloc((st->stacksize + STACKINCREMENT) * sizeof(ElemType));
if(s == NULL)
{
return;
}
for(int i = 0;i < st->top;i++ )
{
s[i] = st->elem[i];
}
free(st->elem);
st->elem = s;
st->stacksize += STACKINCREMENT;
}
入栈
void Push(PStack st,ElemType val)
{
/*
1.是否为有效栈
2.判满,是否需要扩容
3.将val入栈
*/
assert(st != NULL);
if(st == NULL)
{
printf("Push : : 栈无效\n");
exit(0);
}
if(st->top == st->stacksize)
{
AppendStack(st);
}
st->elem[st->top++] = val;
}
出栈
void Pop(PStack st)
{
assert(st != NULL);
if(st == NULL)
{
printf("Pop: : 栈无效\n");
exit(0);
}
if(IsEmpty(st))
{
return;
}
st->top--;
}
获取栈顶元素
ElemType Top(PStack st)
{
assert(st != NULL);
if(st == NULL)
{
printf("Top: : 栈无效\n");
exit(0);
}
return st->elem[st->top - 1];
}
获取栈内元素个数
int Size(PStack st)
{
assert(st != NULL);
if(st == NULL)
{
printf("Size: : 栈无效\n");
exit(0);
}
return st->top ;
}
清空,只是清空栈的元素!
void ClearStack(PStack st)//只是清空栈的元素
{
assert(st != NULL);
if(st == NULL)
{
printf("ClearStack: : 栈无效\n");
exit(0);
}
st->top = 0;
}
销毁,回收内存
void DestroyStack(PStack st)
{
assert(st != NULL);
if(st == NULL)
{
printf("DestroyStack: : 栈无效\n");
exit(0);
}
free(st->elem);
st->elem = NULL;
st->stacksize = st->top = 0;
}
应用
中缀表达式转后缀表达式

void MidToLast(const char *str)
{
SqStack st;
InitStack(&st);
char c = 0;
const char *p = str;
while(*p)
{
if(isdigit(*p))
{
printf("%c",*p);
p++;
continue;
}
switch(*p)
{
case '(':
Push(&st,*p);
break;
case ')':
while(1)
{
c = Top(&st);
Pop(&st);
if(c == '(')
{
break;
}
printf("%c",c);
}
case '*':
case '/':
while(!IsEmpty(&st))
{
c = Top(&st);
if(c == '(' || c == '+' || c == '-')
{
break;
}
Pop(&st);
printf("%c",c);
}
Push(&st,*p);
break;
case '+':
case '-':
while(!IsEmpty(&st))
{
c = Top(&st);
if(c == '(' )
{
break;
}
Pop(&st);
printf("%c",c);
}
Push(&st,*p);
break;
}
p++;
}
//将栈中的剩余内容全部出栈
while(!IsEmpty(&st))
{
c = Top(&st);
Pop(&st);
printf("%c",c);
}
DestroyStack(&st);
}
经典题目
两个栈实现队列
基本思想:
定义两个栈,栈st1用于实现队列的入队列操作,另外一个st2用于实现出队列和取队头元素的操作,已知对栈的操作借助已完成的对顺序栈的操作。如果做pop和peak操作,都从s2的栈顶直接操作,如果s2为空,把s1里面的元素全部倒过来。
结构设计
typedef struct Que
{
SqStack st1;
SqStack st2;
}StackQue;
初始化
void InitStackQue(StackQue *que)
{
assert(que != NULL);
if(que == NULL)
{
printf("StackQue Error\n");
exit(0);
}
InitStack(&que->st1);
InitStack(&que->st2);
}
判空
两个栈均为空,那么这个队列就为空
int IsEmptyStackQue(StackQue *que)
{
assert(que != NULL);
if(IsEmpty(&que->st1) && IsEmpty(&que->st2))
return 1;
}
判满
因为在对栈操作时,已经考虑了栈满时的扩容操作,因此,栈不可能满,所以队列也不会满。
int IsFullStackQue(StackQue *que)
{
return 0;
}
入队列
int PushStackQue(StackQue *que,ElemType val)
{
assert(que != NULL);
if(IsFullStackQue(que))
{
return 0;
}
Push(&que->st1,val);
return 1;
}
出队列
基本思路:
1.当两个栈都为空时,说明这个队列为空,直接退出
2.当st1和st2均不为空时,先将st2中的元素全部弹出,在将st1中的剩余元素弹出并入到st2中,再弹出st2。
3.st1为空,st2不为空时,直接对st2做弹栈操作即可。
3.st1不为空,st2为空时,先将st2中的元素全部弹出,在将st1中的剩余元素弹出并入到st2中,再弹出st2。
4.完成上述23操作后,st2肯定非空,直接对st2做弹栈操作即可。
int PopStackQue(StackQue *que,ElemType *rtval)
{
assert(que != NULL);
//空队列
if(IsEmptyStackQue(que))
{
return 0;
}
//st2为空时
if(IsEmpty(&que->st2))
{
//将st1中的所有元素导到st2中
while(!IsEmpty(&que->st1))
{
ElemType tmp = Top(&que->st1);
Push(&que->st2,tmp);
Pop(&que->st1);
}
}
//接下来st2肯定非空
*rtval = Top(&que->st2);
Pop(&que->st2);
return 1;
}
C++实现
class MyQueue {
public:
MyQueue() {
}
void push(int x) {
s1.push(x);
}
int pop() {
if(s2.empty())
{
while(!s1.empty())
{
s2.push(s1.top());
s1.pop();
}
}
int val = s2.top();
s2.pop();
return val;
}
int peek() {
if(s2.empty())
{
while(!s1.empty())
{
s2.push(s1.top());
s1.pop();
}
}
return s2.top();
}
bool empty() {
return s1.empty()&&s2.empty();
}
private:
stack<int> s1;
stack<int> s2;
};
2897

被折叠的 条评论
为什么被折叠?



