九个动画组图轮播总结全栈数据结构数组链表

目录
  • 一、概念
    • 1、栈的定义
    • 2、栈顶
    • 3、栈底
  • 二、接口
    • 1、可写接口
      • 1)数据入栈
      • 2)数据出栈
      • 3)清空栈
    • 2、只读接口
      • 1)获取栈顶数据
      • 2)获取栈元素个数
      • 3)栈的判空
  • 三、栈的顺序表实现
    • 1、数据结构定义
    • 2、入栈
      • 1、动画演示
      • 2、源码详解
    • 3、出栈
      • 1、动画演示
      • 2、源码详解
    • 4、清空栈
      • 1、动画演示
      • 2、源码详解
    • 5、只读接口
    • 6、栈的顺序表实现源码
  • 四、栈的链表实现
    • 1、数据结构定义
    • 2、入栈
      • 1、动画演示
      • 2、源码详解
    • 3、出栈
      • 1、动画演示
      • 2、源码详解
    • 4、清空栈
      • 1、动画演示
      • 2、源码详解
    • 5、只读接口
    • 6、栈的链表实现源码
  • 五、两种实现的优缺点
    • 1、顺序表实现
    • 2、链表实现

「栈」

栈可以用顺序表实现,也可以用链表实现,浓缩为以下两张图:

看不懂没有关系,我会把它拆开来一个一个讲。

一、概念

1、栈的定义

栈是仅限在表尾进行插入和删除的线性表。

栈又被称为后进先出(LastInFirstOut)的线性表,简称LIFO。

2、栈顶

栈是一个线性表,我们把允许插入和删除的一端称为栈顶。

3、栈底

和栈顶相对,另一端称为栈底,实际上,栈底的元素我们不需要关心。

二、接口

1、可写接口

1)数据入栈

栈的插入操作,叫做入栈,也可称为进栈、压栈。如下图所示,代表了三次入栈操作:

2)数据出栈

栈的删除操作,叫做出栈,也可称为弹栈。如下图所示,代表了两次出栈操作:

3)清空栈

一直出栈,直到栈为空,如下图所示:

2、只读接口

1)获取栈顶数据

对于一个栈来说只能获取栈顶数据,一般不支持获取其它数据。

2)获取栈元素个数

栈元素个数一般用一个额外变量存储,入栈时加一,出栈时减一。这样获取栈元素的时候就不需要遍历整个栈。通过O(1)O(1)O(1)的时间复杂度获取栈元素个数。

3)栈的判空

当栈元素个数为零时,就是一个空栈,空栈不允许出栈操作。

三、栈的顺序表实现

1、数据结构定义

对于顺序表,在C语言中表现为数组,在进行栈的定义之前,我们需要考虑以下几个点:

1)栈数据的存储方式,以及栈数据的数据类型;

2)栈的大小;

3)栈顶指针;

我们可以定义一个栈的结构体,C语言实现如下所示:

#define DataType int        // (1)
#define maxn 100005         // (2)

struct Stack {              // (3)
    DataType data[maxn];    // (4)
    int top;                // (5)
};

(1)用DataType这个宏定义来统一代表栈中数据的类型,这里将它定义为整型,根据需要可以定义成其它类型,例如浮点型、字符型、结构体等等;

(2)maxn代表我们定义的栈的最大元素个数;

(3)Stack就是我们接下来会用到的栈结构体;

(4)DataTypedata[maxn]作为栈元素的存储方式,数据类型为DataType,可以自行定制;

(5)top即栈顶指针,data[top-1]表示栈顶元素,top==0代表空栈;

2、入栈

1、动画演示

如图所示,蓝色元素为原本在栈中的元素,红色元素为当前需要入栈的元素,执行完毕以后,栈顶指针加一。具体来看下代码实现。

2、源码详解

入栈操作,算上函数参数列表,总共也才几句话,代码实现如下:

void StackPushStack(struct Stack *stk, DataType dt) { // (1)
    stk->data[ stk->top ] = dt;                       // (2)
    stk->top = stk->top + 1;                          // (3)
}

(1)stk是一个指向栈对象的指针,由于这个接口会修改栈对象的成员变量,所以这里必须传指针,否则,就会导致函数执行完毕,传参对象没有任何改变;

(2)将传参的元素放入栈中;

(3)将栈顶指针自增1;

注意,这个接口在调用前,需要保证栈顶指针小于栈元素最大个数,即stk->top<maxn,

如果C语言写的熟练,我们可以把(2)(2)(2)和(3)(3)(3)合成一句话,如下:

void StackPushStack(struct Stack *stk, DataType dt) {
    stk->data[ stk->top++ ] = dt;
}

stk->top++表达式的值是自增前的值,并且自身进行了一次自增。

3、出栈

1、动画演示

如图所示,蓝色元素为原本在栈中的元素,红色元素为当前需要出栈的元素,执行完毕以后,栈顶的指针减一。具体来看下代码实现。

2、源码详解

出栈操作,只需要简单改变将栈顶减一即可,代码实现如下:

void StackPopStack(struct Stack* stk) {
    --stk->top;
}

4、清空栈

1、动画演示

如图所示,对于数组来说,清空栈的操作只需要将栈顶指针置为栈底,也就是数组下标0即可,下次继续入栈的时候会将之前的内存重复利用。

2、源码详解

清空栈的操作只需要将栈顶指针直接指向栈底即可,对于顺序表,也就是C语言中的数组来说,栈底就是下标0的位置了,代码实现如下:

void StackClear(struct Stack* stk) {
    stk->top = 0;
}

5、只读接口

只读接口包含:获取栈顶元素、获取栈大小、栈的判空,实现如下:

DataType StackGetTop(struct Stack* stk) {
    return stk->data[ stk->top - 1 ];      // (1)
}
int StackGetSize(struct Stack* stk) {
    return stk->top;                       // (2)
}
bool StackIsEmpty(struct Stack* stk) {
    return !StackGetSize(stk);             // (3)
}

(1)数组中栈元素从0开始计数,所以实际获取元素时,下标为栈顶元素下标减一;

(2)因为只有在入栈的时候,栈顶指针才会加一,所以它正好代表了栈元素个数;

(3)当栈元素个数为零时,栈为空。

6、栈的顺序表实现源码

栈的顺序表实现的源码如下:

/************************************* 栈的顺序表实现 *************************************/
#define DataType int
#define bool int
#define maxn 100010

struct Stack {
    DataType data[maxn];
    int top;
};

void StackClear(struct Stack* stk) {
    stk->top = 0;
}
void StackPushStack(struct Stack *stk, DataType dt) {
    stk->data[ stk->top++ ] = dt;
}
void StackPopStack(struct Stack* stk) {
    --stk->top;
}
DataType StackGetTop(struct Stack* stk) {
    return stk->data[ stk->top - 1 ];
}
int StackGetSize(struct Stack* stk) {
    return stk->top;
}
bool StackIsEmpty(struct Stack* stk) {
    return !StackGetSize(stk);
}
/************************************* 栈的顺序表实现 *************************************/

四、栈的链表实现

1、数据结构定义

对于链表,在进行栈的定义之前,我们需要考虑以下几个点: 1)栈数据的存储方式,以及栈数据的数据类型; 2)栈的大小; 3)栈顶指针;

我们可以定义一个栈的结构体,C语言实现如下所示:

typedef int DataType;             // (1)
struct StackNode;                 // (2)
struct StackNode {                // (3)
    DataType data;
    struct StackNode *next;
};
struct Stack {
    struct StackNode *top;        // (4)
    int size;                     // (5)
};

(1)栈结点元素的数据域,这里定义为整型;

(2)structStackNode;是对链表结点的声明;

(3)定义链表结点,其中DataTypedata代表数据域;structStackNode*next代表指针域;

(4)top作为栈顶指针,当栈为空的时候,top==NULL;否则,永远指向栈顶;

(5)由于求链表长度的算法时间复杂度是O(n)O(n)O(n)的,所以我们需要记录一个size来代表现在栈中有多少元素。每次入栈时size自增,出栈时size自减。这样在询问栈的大小的时候,就可以通过O(1)O(1)O(1)的时间复杂度。

2、入栈

1、动画演示

如图所示,head为栈顶,tail为栈底,vtx为当前需要入栈的元素,即图中的橙色结点。入栈操作完成后,栈顶元素变为vtx,即图中绿色结点。

2、源码详解

入栈操作,其实就是类似头插法,往链表头部插入一个新的结点,代码实现如下:

void StackPushStack(struct Stack *stk, DataType dt) {
    struct StackNode *insertNode = (struct StackNode *) malloc( sizeof(struct StackNode) ); // (1)
    insertNode->next = stk->top;     // (2)
    insertNode->data = dt;           // (3)
    stk->top = insertNode;           // (4)
    ++ stk->size;                    // (5)
}

1)利用malloc生成一个链表结点insertNode;

(2)将当前栈顶作为insertNode的后继结点;

(3)将insertNode的数据域设置为传参dt;

(4)将insertNode作为新的栈顶;

(5)栈元素加一;

3、出栈

1、动画演示

如图所示,head为栈顶,tail为栈底,temp为当前需要出栈的元素,即图中的橙色结点。出栈操作完成后,栈顶元素变为之前head的后继结点,即图中绿色结点。

2、源码详解

出栈操作,由于链表头结点就是栈顶,其实就是删除这个链表的头结点的过程。代码实现如下:

void StackPopStack(struct Stack* stk) {
    struct StackNode *temp = stk->top;  // (1)
    stk->top = temp->next;              // (2)
    free(temp);                         // (3)
    --stk->size;                        // (4)
}

(1)将栈顶指针保存到temp中;

(2)将栈顶指针的后继结点作为新的栈顶;

(3)释放之前栈顶指针对应的内存;

(4)栈元素减一;

4、清空栈

1、动画演示

清空栈可以理解为,不断的出栈,直到栈元素个数为零。

2、源码详解

对于链表而言,清空栈的操作需要删除每个链表结点,代码实现如下:

void StackClear(struct Stack* stk) {
    while(!StackIsEmpty(stk)) {       // (1)
        StackPopStack(stk);           // (2)
    }
    stk->top = NULL;                  // (3)
}

(1)-(2)的每次操作其实就是一个出栈的过程,如果栈不为空;则进行出栈操作,直到栈为空;

(2)然后将栈顶指针置为空,代表这是一个空栈了;

5、只读接口

只读接口包含:获取栈顶元素、获取栈大小、栈的判空,实现如下:

DataType StackGetTop(struct Stack* stk) {
    return stk->top->data;                 // (1)
}
int StackGetSize(struct Stack* stk) {
    return stk->size;                      // (2)
}
int StackIsEmpty(struct Stack* stk) {
    return !StackGetSize(stk);
}

(1)stk->top作为栈顶指针,它的数据域data就是栈顶元素的值,返回即可;

(2)size记录的是栈元素个数;

(3)当栈元素个数为零时,栈为空。

6、栈的链表实现源码

栈的链表实现源码如下:

/************************************* 栈的链表实现 *************************************/
typedef int DataType;
struct StackNode;
struct StackNode {
    DataType data;
    struct StackNode *next;
};
struct Stack {
    struct StackNode *top;
    int size;
};
void StackPushStack(struct Stack *stk, DataType dt) {
    struct StackNode *insertNode = (struct StackNode *) malloc( sizeof(struct StackNode) );
    insertNode->next = stk->top;
    insertNode->data = dt;
    stk->top = insertNode;
    ++ stk->size;
}
void StackPopStack(struct Stack* stk) {
    struct StackNode *temp = stk->top;
    stk->top = temp->next;
    --stk->size;
    free(temp);
}
DataType StackGetTop(struct Stack* stk) {
    return stk->top->data;
}
int StackGetSize(struct Stack* stk) {
    return stk->size;
}
int StackIsEmpty(struct Stack* stk) {
    return !StackGetSize(stk);
}
void StackClear(struct Stack* stk) {
    while(!StackIsEmpty(stk)) {
        StackPopStack(stk);
    }
    stk->top = NULL;
    stk->size = 0;
}
/************************************* 栈的链表实现 *************************************/

五、两种实现的优缺点

1、顺序表实现

在利用顺序表实现栈时,入栈和出栈的常数时间复杂度低,且清空栈操作相比链表实现能做到O(1)O(1)O(1),唯一的不足之处是:需要预先申请好空间,而且当空间不够时,需要进行扩容,扩容方式本文未提及,可以参考我们其他相关文章。

2、链表实现

在利用链表实现栈时,入栈和出栈的常数时间复杂度略高,主要是每插入一个栈元素都需要申请空间,每删除一个栈元素都需要释放空间,且清空栈操作是O(n)O(n)O(n)的,直接将栈顶指针置空会导致内存泄漏。好处就是:不需要预先分配空间,且在内存允许范围内,可以一直入栈,没有顺序表的限制。

关于「栈」的内容到这里就结束了。如果还有不懂的问题,可以想方设法找到作者的联系方式,线上沟通交流,希望大家以后多多支持我们!

(0)

相关推荐

  • python全栈知识点总结

    全栈即指的是全栈工程师,指掌握多种技能,并能利用多种技能独立完成产品的人.就是与这项技能有关的都会,都能够独立的完成. 全栈只是个概念,也分很多种类.真正的全栈工程师涵盖了web开发.DBA .爬虫 .测试.运维,要学的内容那是相当的巨量.就web开发方向而言需要学习的内容:前端知识 包括HTML5 CSS3 JS Jquery Ajax,后端至少需要能够熟练使用Django和tornado,当然会flask更好. 扩展资料: 全栈工程师的厉害之处并不是他掌握很多知识,可以一个人干多份工作.而是

  • python全栈开发语法总结

    太多的小伙伴正在学习Python,就说自己以后要做全栈开发,大家知道这是做什么的吗?我们现在所知道的知识点,哪些是以后你要从事这个全栈所需要的呢?从名字上我们可以获知,"全"一样是掌握全部内容,没错,这里就是要自己掌握全部编程技能,足够独立开发的人,因此全栈士不如也说叫"全战士",如果想做,那就看下面能用到的语法吧. 1.中文编码-UTF8字符集 #!/usr/bin/env python # coding:utf8 2.数值 a = 1 b = 2.1 print

  • python全栈要学什么 python全栈学习路线

    IT行业,技术要比学历.年龄.从业经验更为重要,技术水平直接决定就业薪资,想要学好python,首先要先了解精通Python语言基础.Python web开发.Python爬虫.Python数据分析这四大方面. 全栈即指的是全栈工程师,指掌握多种技能,并能利用多种技能独立完成产品的人.就是与这项技能有关的都会,都能够独立的完成. 全栈只是个概念,也分很多种类.真正的全栈工程师涵盖了web开发.DBA .爬虫 .测试.运维,要学的内容那是相当的巨量.就web开发方向而言需要学习的内容:前端知识 包

  • 九个动画组图轮播总结全栈数据结构数组链表

    目录 一.概念 1.栈的定义 2.栈顶 3.栈底 二.接口 1.可写接口 1)数据入栈 2)数据出栈 3)清空栈 2.只读接口 1)获取栈顶数据 2)获取栈元素个数 3)栈的判空 三.栈的顺序表实现 1.数据结构定义 2.入栈 1.动画演示 2.源码详解 3.出栈 1.动画演示 2.源码详解 4.清空栈 1.动画演示 2.源码详解 5.只读接口 6.栈的顺序表实现源码 四.栈的链表实现 1.数据结构定义 2.入栈 1.动画演示 2.源码详解 3.出栈 1.动画演示 2.源码详解 4.清空栈 1.

  • 基于JavaScript实现焦点图轮播效果

        不管是高校的网站还是电商的页面,焦点图的切换和轮播应该是一项不可或缺的应用.今天把焦点图轮播制作的技术要点做下笔记,以供日后查看. 一.结构层(HTML) 焦点图的HTML结构很简单,就是一个父容器(id=box),包含三个子容器,分别存放图片(id=pics).底部按钮(id=dots).作用切换箭头(class=turn).加上样式后就是下图二的布局. 二.表示层(CSS) 页面的表现和风格总是离不开CSS.为叙述方便,后面采用id选择符名或类选择符名代表各div模块. 1.box

  • JS实现焦点图轮播效果的方法详解

    本文实例讲述了JS实现焦点图轮播效果的方法.分享给大家供大家参考,具体如下: 效果图如下: 一.所用到的知识点 1.DOM操作 2.定时器 3.事件运用 4.Js动画 5.函数递归 6.无限滚动大法 二.结构和样式 <div id="banner" class="banner"> <ul id="list-banner" class="list-banner fn-clear" style="lef

  • jQuery焦点图轮播插件KinSlideshow用法分析

    本文实例讲述了jQuery焦点图轮播插件KinSlideshow用法.分享给大家供大家参考,具体如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"

  • jQuery焦点图轮播效果实现方法

    本文实例讲述了jQuery焦点图轮播效果实现方法.分享给大家供大家参考,具体如下: 前面一篇<JS实现焦点图轮播效果的方法详解>详细介绍了JS实现焦点图轮播效果的步骤,这里来分析一下jQuery的相关实现技巧. 核心代码如下: $(function(){ var $next=$(".right"); var $prev=$(".left"); var $list_num=$(".list-num a"); var $banner=$(

  • 微信小程序实现banner图轮播效果

    本文实例为大家分享了微信小程序实现banner图轮播的具体代码,供大家参考,具体内容如下 效果图: indicator-active-color="#007aff"//修改选中图片圆点的颜色 js: const app = getApp() Page({ data: { //-----------模拟banner图----------- imgUrls: [ '/image/1545118381903.jpg', '/image/1545118566631.jpg' ], circul

  • jQuery焦点图轮播特效代码分享(3款)

    本文实例讲述了jQuery焦点图轮播特效代码.分享给大家供大家参考.具体如下: jQuery cxSlide实现的三款多功能大气焦点图轮播特效源码,是一段拥有三种不同风格和效果的焦点图轮播代码,其中有两款最有意思,一款是在将焦点图图片分成了四块,每个图片都连接到不同的地址,并且还拥有鼠标悬浮内图时,其它图片都变暗了的效果,另外一款是,带有带缩略图和文字描述效果的焦点图轮播代码. 运行效果图: ----------------------查看效果 源码下载---------------------

  • uniapp vue与nvue轮播图 轮播图组件

    vue部分如下: <template> <view class=""> <!-- 轮播图组件 --> <swiper :indicator-dots="true" :autoplay="true" :interval="3000" :duration="1000" circular=""> <block v-for="(it

  • react基于react-slick实现多图轮播效果

    目录 写在前面: 一.进入官网查看文档(Docs) 二.安装插件(Quick Start) 三.范例使用(Examples) 1.直接copy代码: 2.实现结果: 3.引入样式: 4.还是报错? 5.运行成功! 实现结果: 总结 写在前面: 目前在项目中有轮播图需求,但是antd组件不能实现多张图片的轮播(或许是我没找到相应方法) 最后找到react-slick插件,能实现想要的效果 一.进入官网查看文档(Docs) react-slick官网 二.安装插件(Quick Start) //np

  • jQuery动画效果图片轮播特效

    从这一章节开始,我将会为大家陆续的介绍利用Jquery完成特效动画.先来看看这一节所介绍的特效:传统轮播. 一.需求分析 1. 提供很多尺寸相等的图片,一排紧挨着显示. 2. 左右有两个切换按钮,用来控制显示上一张还是下一张. 3. 右下方有指示器"小圈圈",用来提示显示到第几个图片:也可以点击它,进行图片的切换. 4. 每隔一个固定的时间,图片会自动滚动. 5. 当鼠标放到图片上面的时候,会停止自动滚动:当鼠标离开后,再经过固定间隔时间后,又会自动播放. 二.代码剖析 1. 用htm

随机推荐