数据结构&算法08-栈概念&源码

Posted 李柱明

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构&算法08-栈概念&源码相关的知识,希望对你有一定的参考价值。


前言

李柱明博客:https://www.cnblogs.com/lizhuming/p/15487342.html

栈的定义

定义

栈(stack)是限定仅在表尾进行插入和删除操作的线性表。

  • 栈首先是一个线性表,栈元素具有线性关系。为特殊的线性表。
  • 栈顶(top):允许插入和删除的一端称为栈顶。
  • 栈底(bottom):另一端称为栈底。
  • 表尾指的是栈顶,而不是栈底。
  • 空栈:不含任何数据元素的栈称为空栈。
  • LIFO:last in first out,栈又称为后进先出的线性表,简称 LIFO 结构。
  • 栈的插入操作:进栈,也称压栈、入栈。
  • 栈的删除操作:出栈,也称弹栈。
  • 用数组实现的栈叫做:顺序栈
  • 用链表实现的栈叫做:链式栈

小笔记:

  • 内存中的堆栈和数据结构堆栈不是一个概念:

    • 内存中的堆栈是真实存在的物理区。内存空间在逻辑上分为三部分:代码区、静态数据区和动态数据区,动态数据区又分为栈区和堆区。

      • 代码区 :存储方法体的二进制代码。高级调度(作业调度)、中级调度(内存调度)、低级调度(进程调度)控制代码区执行代码的切换。
      • 静态数据区 :存储全局变量、静态变量、常量,常量包括 final 修饰的常量和 String 常量。系统自动分配和回收。
      • 栈区 :存储运行方法的形参、局部变量、返回值。由系统自动分配和回收。例如 int method(int a){int b;}栈中存储参数 a、局部变量 b、返回值 temp。
      • 堆区 :new 一个对象的引用或地址存储在栈区,指向该对象存储在堆区中的真实数据。由程序员分配和回收。
    • 数据结构中的堆栈是抽象的数据存储结构。

      • :是一种连续存储的数据结构,特点是存储的数据先进后出。
      • :是一棵完全二叉树结构,特点是父节点的值大于(小于)两个子节点的值(分别称为大顶堆和小顶堆)。它常用于管理算法执行过程中的信息,应用场景包括堆排序,优先队列等。

常见应用

栈相对于数组和链表来说只有限制,是操作受限的线性表。从功能上,数组和链表也可以代替栈,但是数组或链表暴露了太多的操作接口,操作上的确灵活自由,但使用时就比较不可控,自然也就更容易出错。

栈的常见应用

  • 软件中的撤销(undo)操作,浏览器历史纪录,android 中的最近任务,Activity 的启动模式,CPU 中栈的实现,Word 自动保存,解析计算式,解析 xml/json。

进栈出栈变化形式

出栈序列个数公式:卡特兰公式:C(2n,n)/(n+1)

  • n 为前几个数时的值:1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796 ...

栈的抽象数据类型

栈为线性表,具备线性表的操作特性。

对于栈来说,插入和删除改名为 push 和 pop。

栈的顺序存储结构及实现

栈的顺序存储结构

顺序栈

  • 栈的顺序存储也是线性表顺序存储的简化,简称为顺序栈。
  • 在数组中,用下标为 0 的一段作为栈底。
  • 栈顶 top:若存储栈长度为 stack_size,则 top 必须少于 stack_size。
  • 空栈:栈中有一个元素时,top=0。空栈时,top = -1。

顺序栈的结构定义

  • 指针式
// 指针式
typedef int se_type; /* 元素类型 */
typedef struct
{
    se_type *top;           /* 栈顶指针 */
    se_type *bottom;        /* 栈底指针 */
    se_type stack_size;     /* 栈的最大容量 */
}stack_t;
  • 数组式
// 数组式
typedef int se_type; /* 元素类型 */
#define STACK_SIZE 100 /* 栈元素个数 */
typedef struct
{
    int top;                    /* 栈顶指针 */
    se_type data[STACK_SIZE];   /* 栈空间 */
}stack_t;

两栈共享空间

两栈共享空间

  • 原理:两个栈底分别位于数组的始端(下标 0)和数组的末端(下标数组长度 n-1),增加元素即从两端点向中间延伸。

  • 条件:两个具有相同数据类型的栈,生长方向相反。

  • 满栈判断:

    • 一般情况:两个栈见面之时,即两个指针相差 1,top1+1 == top2 时。
    • 极端情况:stack_2 空时,top1=n-1,则 stack_1 满;stack_1 空,top2=0,则 stack_2 满。

部分代码实现

// 数组式
/* 两栈共享空间结构 */
typedef int se_type; /* 元素类型 */
#define STACK_SIZE 100 /* 栈元素个数 */
typedef struct
{
    int top1;                    /* 栈顶指针 */
    int top2;                    /* 栈顶指针 */
    se_type data[STACK_SIZE];    /* 栈空间 */
}stack_double_t;

/**
 * @name   stack_double_creat
 * @brief  
 * @param  
 * @retval 
 * @author lzm
 */
stack_double_t *stack_double_creat(void)
{
    stack_t *stack_double_ptr = NULL;

    stack_double_ptr = (stack_double_t *)malloc(sizeof(stack_double_t));
    if(stack_double_ptr == NULL)
        return NULL;
    memset(stack_ptr, 0x00, sizeof(stack_double_t));

    stack_double_ptr->top1 = -1;
    stack_double_ptr->top2 = STACK_SIZE;

    return stack_double_ptr;
}

/**
 * @name   stack_double_destroy
 * @brief  
 * @param  
 * @retval 
 * @author lzm
 */
int stack_double_destroy(stack_double_t *stack)
{
    if(stack != NULL)
    {
        free(stack);
        return 0;
    }

    return -1;
}

栈的链式存储结构及实现

栈的链式存储结构

就是基于链表实现的栈。

栈的链式存储结构:

  • 栈的链式存储结构,简称链栈。
  • 栈顶放在单链表的头部,且不需要头结点。(自主决定
  • 空栈:链表原定义为头指针指向空,故链栈的空是 top = NULL。
  • 结构:
/* 链式结构 */
typedef int se_type; /* 元素类型 */
typedef struct stack_node
{
    se_type date;
    struct stack_node *next;
}stack_node_t;

typedef struct
{
    int count;
    stack_node_t *top;
}stack_link_t;

栈的应用之递归

递归的定义:

  • 把一个直接调用自己或者通过一系列的调用语句间接地调用自己的函数,称为递归函数。
  • 每个递归定义必须至少有一个条件,满足时递归不再进行,即不再引用自身而是返回值退出。(出口条件)

递归与栈结构:

  • 递归进入时,压栈。
  • 递归退出时,出栈。

代码实现

指针式顺序栈操作

/** @file         stack.c
 *  @brief        简要说明
 *  @details      详细说明
 *  @author       lzm
 *  @date         2021-09-06 09:42:22
 *  @version      v1.0
 *  @copyright    Copyright By lizhuming, All Rights Reserved
 *  @blog         https://www.cnblogs.com/lizhuming/
 *
 **********************************************************
 *  @LOG 修改日志:
 **********************************************************
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 指针式
typedef int se_type; /* 元素类型 */
typedef struct
{
    se_type *top;           /* 栈顶指针 */
    se_type *bottom;        /* 栈底指针 */
    se_type stack_size;     /* 栈的最大容量,元素个数。 */
}stack_pointer_t;


/**
 * @name   stack_pointer_creat
 * @brief  
 * @param  
 * @retval 
 * @author lzm
 */
stack_pointer_t *stack_pointer_creat(int size)
{
    stack_pointer_t *stack_ptr = NULL;

    stack_ptr = (stack_pointer_t *)malloc(sizeof(stack_pointer_t));
    if(stack_ptr == NULL)
        return NULL;
    memset(stack_ptr, 0x00, sizeof(stack_pointer_t));

    stack_ptr->bottom = (se_type *)malloc(size * sizeof(se_type));
    if(stack_ptr->bottom == NULL)
    {
        free(stack_ptr);
        return NULL;
    }
    memset(stack_ptr->bottom, 0x00, size * sizeof(se_type));

    stack_ptr->top = stack_ptr->bottom;
    stack_ptr->stack_size = size;

    return stack_ptr;
}

/**
 * @name   stack_pointer_destroy
 * @brief  
 * @param  
 * @retval 
 * @author lzm
 */
int stack_pointer_destroy(stack_pointer_t *stack)
{
    if(stack != NULL)
    {
        if(stack->bottom != NULL)
            free(stack->bottom);

        free(stack);

        return 0;
    }

    return -1;
}

/**
 * @name   stack_pointer_clear
 * @brief  
 * @param  
 * @retval 
 * @author lzm
 */
int stack_pointer_clear(stack_pointer_t *stack)
{
    if(stack == NULL)
        return -1;

    stack->top = stack->bottom;

    return 0;
}

/**
 * @name   stack_pointer_empty
 * @brief  
 * @param  
 * @retval 
 * @author lzm
 */
int stack_pointer_empty(stack_pointer_t *stack)
{
    if(stack == NULL)
        return -1;

    if(stack->top == stack->bottom)
        return 1;
  
    return 0;
}

/**
 * @name   stack_pointer_full
 * @brief  
 * @param  
 * @retval 
 * @author lzm
 */
int stack_pointer_full(stack_pointer_t *stack)
{
    if(stack == NULL)
        return -1;

    if(stack->top == (stack->bottom + stack->stack_size * sizeof(se_type)))
        return 1;
  
    return 0;
}

/**
 * @name   stack_pointer_length
 * @brief  
 * @param  
 * @retval 
 * @author lzm
 */
int stack_pointer_length(stack_pointer_t *stack)
{
    if(stack == NULL)
        return -1;

    return (stack->top - stack->bottom)/sizeof(se_type);
}

/**
 * @name   stack_pointer_push
 * @brief  
 * @param  
 * @retval 
 * @author lzm
 */
int stack_pointer_push(stack_pointer_t *stack, se_type elem)
{
    if(stack_pointer_full(stack) != 0)
        return -1;

    *stack->top = elem;
    stack->top += sizeof(se_type);

    return 0;
}

/**
 * @name   stack_pointer_pop
 * @brief  
 * @param  
 * @retval 
 * @author lzm
 */
int stack_pointer_pop(stack_pointer_t *stack, se_type *elem)
{
    if(stack_pointer_empty(stack) != 0)
    {
        elem = NULL;
        return -1;
    }

    stack->top -= sizeof(se_type);
    elem = stack->top;

    return 0;
}

int main(void)
{
	;
}

数组式顺序栈操作

/** @file         stack.c
 *  @brief        简要说明
 *  @details      详细说明
 *  @author       lzm
 *  @date         2021-09-06 09:42:22
 *  @version      v1.0
 *  @copyright    Copyright By lizhuming, All Rights Reserved
 *  @blog         https://www.cnblogs.com/lizhuming/
 *
 **********************************************************
 *  @LOG 修改日志:
 **********************************************************
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 数组式
typedef int se_type; /* 元素类型 */
#define STACK_SIZE 100 /* 栈元素个数 */
typedef struct
{
    int top;                    /* 栈顶指针 */
    se_type data[STACK_SIZE];   /* 栈空间 */
}stack_t;

/**
 * @name   stack_creat
 * @brief  
 * @param  
 * @retval 
 * @author lzm
 */
stack_t *stack_array_creat(void)
{
    stack_t *stack_ptr = NULL;

    stack_ptr = (stack_t *)malloc(sizeof(stack_t));
    if(stack_ptr == NULL)
        return NULL;
    memset(stack_ptr, 0x00, sizeof(stack_t));

    stack_ptr->top = -1;

    return stack_ptr;
}

/**
 * @name   stack_destroy
 * @brief  
 * @param  
 * @retval 
 * @author lzm
 */
int stack_array_destroy(stack_t *stack)
{
    if(stack != NULL)
    {
        free(stack);
        return 0;
    }

    return -1;
}

/**
 * @name   stack_clear
 * @brief  
 * @param  
 * @retval 
 * @author lzm
 */
int stack_array_clear(stack_t *stack)
{
    if(stack == NULL)
        return -1;

    stack->top = -1;

    return 0;
}

/**
 * @name   stack_empty
 * @brief  
 * @param  
 * @retval 
 * @author lzm
 */
int stack_array_empty(stack_t *stack)
{
    if(stack == NULL)
        return -1;

    if(stack->top == -1)
        return 1;
  
    return 0;
}

/**
 * @name   stack_full
 * @brief  
 * @param  
 * @retval 
 * @author lzm
 */
int stack_array_full(stack_t *stack)
{
    if(stack == NULL)
        return -1;

    if(stack->top == STACK_SIZE-1)
        return 1;
  
    return 0;
}

/**
 * @name   stack_length
 * @brief  
 * @param  
 * @retval 
 * @author lzm
 */
int stack_array_length(stack_t *stack)
{
    if(stack == NULL)
        return -1;

    return stack->top + 1;
}

/**
 * @name   stack_push
 * @brief  
 * @param  
 * @retval 
 * @author lzm
 */
int stack_array_push(stack_t *stack, se_type elem)
{
    if(stack_array_full(stack) != 0)
        return -1;

    stack->top++;
    stack->data[stack->top] = elem;

    return 0;
}

/**
 * @name   stack_pop
 * @brief  
 * @param  
 * @retval 
 * @author lzm
 */
int stack_array_pop(stack_t *stack, se_type *elem)
{
    if(stack_array_empty(stack) != 0 || elem == NULL)
    {
        return -1;
    }

    *elem = stack->data[stack->top];
    stack->top--;

    return 0;
}

/**
 * @name   stack_get_top
 * @brief  
 * @param  
 * @retval 
 * @author lzm
 */
int stack_array_get_top(stack_t *stack, se_type *elem)
{
    if(stack_array_empty(stack) != 0 || elem == NULL || stack->top >= STACK_SIZE)
    {
        return -1;
    }

    *elem = stack->data[stack->top];

    return 0;
}

链式栈

/** @file         stack.c
 *  @brief        简要说明
 *  @details      详细说明
 *  @author       lzm
 *  @date         2021-09-06 22:52:12
 *  @version      v1.0
 *  @copyright    Copyright By lizhuming, All Rights Reserved
 *  @blog         https://www.cnblogs.com/lizhuming/
 *
 **********************************************************
 *  @LOG 修改日志:
 **********************************************************
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* 链式结构 */
typedef int se_type; /* 元素类型 */
typedef struct stack_node
{
    se_type date;
    struct stack_node *next;
}stack_node_t;

typedef struct
{
    int count;
    stack_node_t *top;
}stack_link_t;


/**
 * @name   stack_link_creat
 * @brief  
 * @param  
 * @retval 
 * @author lzm
 */
stack_link_t *stack_creat(int size)
{
    stack_link_t *stack_ptr = NULL;

    stack_ptr = (stack_link_t *)malloc(sizeof(stack_link_t));
    if(stack_ptr == NULL)
        return NULL;
    memset(stack_ptr, 0x00, sizeof(stack_link_t));

    stack_ptr->count = 0;
    stack_ptr->top = NULL;

    return stack_ptr;
}

/**
 * @name   stack_link_destroy
 * @brief  
 * @param  
 * @retval 
 * @author lzm
 */
int stack_link_destroy(stack_link_t *stack)
{
    stack_node_t *stack_cur = NULL;
    stack_node_t *stack_last = NULL;

    if(stack == NULL)
        return -1;
  
    stack_cur = stack->top;
    while(stack_cur)
    {
        stack_last = stack_cur;
        stack_cur = stack_cur->next;
        free(stack_last);
    }

    free(stack);

    return 0;
}

/**
 * @name   stack_link_clear
 * @brief  
 * @param  
 * @retval 
 * @author lzm
 */
int stack_link_clear(stack_link_t *stack)
{
    stack_node_t *stack_cur = NULL;
    stack_node_t *stack_last = NULL;

    if(stack == NULL)
        return -1;
  
    stack_cur = stack->top;
    while(stack_cur)
    {
        stack_last = stack_cur;
        stack_cur = stack_cur->next;
        free(stack_last);
    }

    return 0;
}

/**
 * @name   stack_link_empty
 * @brief  
 * @param  
 * @retval 
 * @author lzm
 */
int stack_link_empty(stack_link_t *stack)
{
    if(stack == NULL)
        return -1;

    if(stack->count == 0)
        return 1;
  
    return 0;
}

/**
 * @name   stack_link_length
 * @brief  
 * @param  
 * @retval 
 * @author lzm
 */
int stack_link_length(stack_link_t *stack)
{
    if(stack == NULL)
        return -1;

    return (stack->count);
}

/**
 * @name   stack_link_push
 * @brief  
 * @param  
 * @retval 
 * @author lzm
 */
int stack_link_push(stack_link_t *stack, se_type elem)
{
    stack_node_t *stack_node_ptr = NULL;

    stack_node_ptr = (stack_node_t *)malloc(sizeof(stack_node_t));
    if(stack_node_ptr == NULL)
        return -1;
    memset(stack_node_ptr, 0x00, sizeof(stack_node_t));

    stack_node_ptr->date = elem;
    stack_node_ptr->next = stack->top;
    stack->top = stack_node_ptr->next;
    stack->count++;

    return 0;
}

/**
 * @name   stack_link_pop
 * @brief  
 * @param  
 * @retval 
 * @author lzm
 */
int stack_link_pop(stack_link_t *stack, se_type *elem)
{
    stack_node_t *node = NULL;
    if(stack_link_empty(stack) != 0 || elem == NULL)
    {
        return -1;
    }

    *elem = stack->top->date;
    node = stack->top;
    stack->top = stack->top->next;
    free(node);
    stack->count--;

    return 0;
}

/**
 * @name   stack_link_get_top
 * @brief  
 * @param  
 * @retval 
 * @author lzm
 */
int stack_link_get_top(stack_link_t *stack, se_type *elem)
{
    if(stack_link_empty(stack) != 0 || elem == NULL)
    {
        return -1;
    }

    *elem = stack->top->date;

    return 0;
}

数据结构&算法-共享栈

概念

共享栈:两个栈共享同一片存储空间,这片存储空间不单独属于任何一个栈,某个栈需要的多一点,它就可能得到更多的存储空间;
两个栈的栈底在这片存储空间的两端,当元素入栈时,两个栈的栈顶指针相向而行。

图示

运行结果

代码

using System;

namespace SharingStack

    class Program
    
        static void Main(string[] args)
        
            SharingStackC<string> sharingStackC = new SharingStackC<string>(5);
          
            sharingStackC.Push("龙", 1);
            sharingStackC.Push("猴", 2);
            Console.WriteLine(sharingStackC.Pop(1));
            Console.WriteLine(sharingStackC.Pop(2));
            Console.WriteLine("-----------------------------");

            sharingStackC.Push("蛇", 1);
            sharingStackC.Push("马", 1);
            sharingStackC.Push("羊", 1);
            sharingStackC.Push("虎", 1);
            sharingStackC.Push("兔", 1);
            sharingStackC.Push("牛", 1);
            Console.WriteLine("-----------------------------");

            while (sharingStackC.Stack1Count > 0)
            
                Console.WriteLine(sharingStackC.Pop(1));
            
            sharingStackC.Push("牛", 2);
            sharingStackC.Push("鼠", 2);
            sharingStackC.Push("白", 2);
            Console.WriteLine("-----------------------------");

            while (sharingStackC.Stack2Count > 0)
            
                Console.WriteLine(sharingStackC.Pop(2));
            
        
    

    /// <summary>
    /// 共享栈
    /// </summary>
    /// <typeparam name="DataT"></typeparam>
    class SharingStackC<DataT>
    

        DataT[] totalCapacoty;
        int stack1Top;
        int stack2Top;

        /// <summary>
        /// 一号栈数量
        /// </summary>
        public int Stack1Count
        
            get  return stack1Top + 1; 
        
        /// <summary>
        /// 二号栈数量
        /// </summary>
        public int Stack2Count
        
            get  return totalCapacoty.Length - stack2Top; 
        

        /// <summary>
        /// 空间大小
        /// </summary>
        /// <param name="count"></param>
        public SharingStackC(int count)
        
            if (count < 1)
            
                throw new Exception("空间大小要大于0");
            

            totalCapacoty = new DataT[count];
            stack1Top = -1;
            stack2Top = totalCapacoty.Length;
        

        /// <summary>
        /// 入栈
        /// </summary>
        /// <param name="data"></param>
        /// <param name="stackNumber"></param>
        public void Push(DataT data, int stackNumber)
        
            if (stack1Top + 1 == stack2Top)
            
                Console.WriteLine("空间已满,0 无法入栈", data);
                return;
            
            if (stackNumber == 1)
            
                stack1Top++;
                totalCapacoty[stack1Top] = data;
            
            else if (stackNumber == 2)
            
                stack2Top--;
                totalCapacoty[stack2Top] = data;

            
        

        /// <summary>
        /// 取数据
        /// </summary>
        /// <param name="stackNumber"></param>
        /// <returns></returns>
        public DataT Peek(int stackNumber)
        

            if (stackNumber == 1 && stack1Top > -1)
            
                return totalCapacoty[stack1Top];
            
            else if (stackNumber == 2 && stack2Top < totalCapacoty.Length)
            
                return totalCapacoty[stack2Top];
            

            return default(DataT);
        
        /// <summary>
        /// 出栈
        /// </summary>
        /// <param name="stackNumber"></param>
        /// <returns></returns>
        public DataT Pop(int stackNumber)
        
            if (stackNumber == 1 && stack1Top > -1)
            
                DataT temp = totalCapacoty[stack1Top];
                stack1Top--;
                return temp;
            
            else if (stackNumber == 2 && stack2Top < totalCapacoty.Length)
            
                DataT temp = totalCapacoty[stack2Top];
                stack2Top++;
                return temp;
            
            return default(DataT);
        
    


参考

一文搞懂共享栈

以上是关于数据结构&算法08-栈概念&源码的主要内容,如果未能解决你的问题,请参考以下文章

数据结构&算法-共享栈

技术栈

数据结构--栈(概念&实现)

javajava两个栈实现一个队列&两个队列实现一个栈

Java 数据结构 & 算法宁可累死自己, 也要卷死别人 5 栈

Day489&490&491.尚硅谷之高频重点面试题③ -面经