关于栈和队列的相关操作

1、栈  分为顺序栈和链栈  对应数组和链表

top指向栈顶元素,设置空栈为-1;存在一个元素时top=0

栈的长度为StackSize

定义栈的结构体:

 1 #include "stdio.h"
 2 
 3 /* 存储空间初始分配量 */
 4 #define MAXSIZE 20
 5 
 6 /* SElemType类型根据实际情况而定,这里假设为int */
 7 typedef int SElemType;
 8 
 9 /* 顺序栈结构 */
10 typedef struct
11 {
12     SElemType data[MAXSIZE];
13     int top; /* 用于栈顶指针 */
14 }SqStack;
15 
16 int main()
17 {
18 }

进栈操作:push

1 int Push(SqStack * S, SElemType e){
2     if(S->top == MAXSIZE-1){
3         //栈满
4         return 0;
5     }
6     S->top++;
7     S->data[S->top] = e;
8     return 1;
9 }

初始化一个空栈:

//初始化栈
int InitStack(SqStack S){
    S->top = -1;
    return 1;
}

栈的遍历:

 1 /* 从栈底到栈顶依次对栈中每个元素显示 */
 2 Status StackTraverse(SqStack S)
 3 {
 4     int i;
 5     i=0;
 6     while(i<=S.top)
 7     {
 8         visit(S.data[i++]);
 9     }
10     printf("
");
11     return OK;
12 }
13 
14 Status visit(SElemType c)
15 {
16     printf("%d ",c);
17     return OK;
18 }

注:S->top代表着栈对应数组的下标0,1,2 。。。

出栈:

1 int Pop(SqStack* S, SElemType* e){
2     if(-1 == S->top){
3         return 0;
4     }
5     *e = S->data[S->top];
6     S->top--;
7     return 1;
8 }

获取栈顶元素:

1 /* 若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR */
2 Status GetTop(SqStack S,SElemType *e)
3 {
4     if (S.top==-1)
5         return ERROR;
6     else
7         *e=S.data[S.top];
8     return OK;
9 }

判断栈是否为

1 /* 若栈S为空栈,则返回TRUE,否则返回FALSE */
2 Status StackEmpty(SqStack S)
3 {
4     if (S.top==-1)
5         return TRUE;
6     else
7         return FALSE;
8 }

置空栈:

1 /* 把S置为空栈 */
2 Status ClearStack(SqStack *S)
3 {
4     S->top=-1;
5     return OK;
6 }

2、链栈

链栈对应不含头结点的单链表

top代表指向栈顶的指针,这里和链表中的next合并为一个,当top=null时,链栈为空

定义链栈的结构体:

下面是单链表的结构体:

1 typedef struct Node
2 {
3     ElemType data;
4     struct Node *next;
5 }Node;
6 typedef struct Node *LinkList; /* 定义LinkList */

相似的链栈的结构体为:

1 /* 链栈结构 */
2 typedef struct StackNode
3 {
4     SElemType data;
5     struct StackNode *next;
6 } StackNode,*LinkStackPtr;

这只是链栈一个节点的定义,还需要添加链栈的栈顶指针:

 1 typedef int Status;
 2 /* SElemType类型根据实际情况而定,这里假设为int */
 3 typedef int SElemType;
 4 
 5 /* 链栈结构 */
 6 typedef struct StackNode
 7 {
 8     SElemType data;
 9     struct StackNode *next;
10 } StackNode,*LinkStackPtr;
11 
12 typedef struct
13 {
14     LinkStackPtr top;
15     int count;
16 } LinkStack;

其中count是用来计算栈中元素的个数的,也可以根据需要添加属性等

入栈,其实就是添加新的节点,下面这张图描述的很清楚:

实际上就两步:1、将新的节点next指向原栈顶元素  2、将top指针指向新的节点

1 int Push(LinkStack* L, SElemType e){
2     //首先分配节点
3     LinkStackPtr p = (LinkStackPtr)malloc(sizeof(StackNode));
4     p->data = e;
5     p->next = S->top;
6     S->top = p;
7     S->count++;
8     return 1;
9 }

初始化空栈:条件count=0,且top为null

 1 /*  构造一个空栈S */
 2 Status InitStack(LinkStack *S)
 3 {
 4     S->top = (LinkStackPtr)malloc(sizeof(StackNode));
 5     if(!S->top)
 6         return ERROR;//分配失败
 7     S->top=NULL;
 8     S->count=0;
 9     return OK;
10 }

遍历的过程和链表完全类似,这里不再赘述:

 1 Status StackTraverse(LinkStack S)
 2 {
 3     LinkStackPtr p;
 4     p=S.top;
 5     while(p)
 6     {
 7         visit(p->data);
 8         p=p->next;
 9     }
10     printf("
");
11     return OK;
12 }
13 
14 Status visit(SElemType c)
15 {
16     printf("%d ",c);
17     return OK;
18 }

出栈操作:这里主要注意一点就是删除的节点要释放掉 核心代码就是S->top = S->top->next;

 1 /* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */
 2 Status Pop(LinkStack *S,SElemType *e)
 3 {
 4     LinkStackPtr p;
 5     if(StackEmpty(*S))
 6         return ERROR;
 7     *e=S->top->data;
 8     p=S->top;                    /* 将栈顶结点赋值给p,见图中① */
 9     S->top=S->top->next;    /* 使得栈顶指针下移一位,指向后一结点,见图中② */
10     free(p);                    /* 释放结点p */
11     S->count--;
12     return OK;
13 }

注:这里的Status是预定义的,这里简化表示int

置空链栈会比顺序栈稍微复杂一些:置空顺序栈只需一步S->top = -1即可,而对于链栈置空实质上就是删除整个链表所有的节点,这里关键的问题就是移动待删除节点指针到下一个位置后,没法直接free掉,这样说起来不好理解,直接看代码:

 1 /* 把S置为空栈 */
 2 Status ClearStack(LinkStack *S)
 3 {
 4     LinkStackPtr p,q;
 5     p=S->top;
 6     while(p)
 7     {
 8         q=p;
 9         p=p->next;
10         free(q);
11     }
12     S->count=0;
13     return OK;
14 }

其实就是先将待删除节点付给一个临时指针,然后当前指针移动到下一个位置后,就可以将这个临时指针给free掉

那这里来分析一下顺序栈和链栈的区别:两者的时间复杂度都为O(1)
顺序栈定位元素更加方便,需提前分配内存区域;链栈在内存充足的情况下大小是无限的,存取定位没有顺序栈快,每个节点还有指针域,某种程度上增加了空间开销

所以根据不同情况选择

原文地址:https://www.cnblogs.com/CoolRandy/p/4921682.html