• 关于栈和队列的相关操作


    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)
    顺序栈定位元素更加方便,需提前分配内存区域;链栈在内存充足的情况下大小是无限的,存取定位没有顺序栈快,每个节点还有指针域,某种程度上增加了空间开销

    所以根据不同情况选择

  • 相关阅读:
    【DNN发布包解释】package 包裹
    数据仓库 SSIS
    【DNN 系列】 添加模块后不显示
    GridView 绑定 ObjectDataSource
    【DNN 系列】 MVC 分页
    关于一级指针和二级指针的简单见解
    高效使用Vector
    关于autoptr
    (转)Win10 + VMware-CentOS7文件共享、网络连接
    Linux 笔记
  • 原文地址:https://www.cnblogs.com/CoolRandy/p/4921682.html
Copyright © 2020-2023  润新知