您的位置:首页 > 新闻 > 资讯 > 学校模板_济南旅游网页设计_公司seo是指什么意思_全媒体运营师报考条件

学校模板_济南旅游网页设计_公司seo是指什么意思_全媒体运营师报考条件

2025/7/3 19:37:55 来源:https://blog.csdn.net/zdoeo/article/details/146427994  浏览:    关键词:学校模板_济南旅游网页设计_公司seo是指什么意思_全媒体运营师报考条件
学校模板_济南旅游网页设计_公司seo是指什么意思_全媒体运营师报考条件

对于逻辑关系为“一对一”的数据,除了用顺序表链表存储外,还可以用栈结构存储。

栈是一种“特殊”的线性存储结构,它的特殊之处体现在以下两个地方:
1、元素进栈和出栈的操作只能从一端完成,另一端是封闭的,如下图所示:

栈存储结构示意图

图 1 栈存储结构示意图

通常,我们将元素进栈的过程简称为“入栈”、“进栈”或者“压栈”;将元素出栈的过程简称为“出栈”或者“弹栈”。

2、栈中无论存数据还是取数据,都必须遵循“先进后出”的原则,即最先入栈的元素最先出栈。以图 1 的栈为例,很容易可以看出是元素 1 最先入栈,然后依次是元素 2、3、4 入栈。在此基础上,如果想取出元素 1,根据“先进后出”的原则,必须先依次将元素 4、3、2 出栈,最后才能轮到元素 1 出栈。

我们习惯将栈的开口端称为栈顶,封口端称为栈底。例如在图 1 中,元素 4 一侧为栈顶,元素 1 一侧为栈底,如图 2 所示。

栈顶和栈底

图 2 栈顶和栈底

由此我们可以对栈存储结构下一个定义:栈一种“只能从一端存取元素,且存取过程必须遵循‘先进后出’原则”的线性存储结构。

栈的具体实现

线性表类似,栈存储结构也有两种具体的实现方案:

  • 顺序栈:用顺序表存储数据,数据存取的过程严格遵循栈结构的规定;
  • 链栈:用链表存储数据,数据存储的过程严格遵循栈结构的规定。

显然,顺序栈和链栈两种实现方案,本质的区别仍然是顺序表和链表之间的区别,即顺序栈是将所有数据集中存储,而链栈是将数据分散存放,元素之间的逻辑关系靠指针维系。

顺序栈的具体实现

顺序指的是用顺序表实现的栈存储结构,通过前面的学习我们知道,栈存储结构存取数据元素必须遵守 "先进后出" 的原则。本节就给大家详细讲解如何使用顺序表模拟栈结构,以及实现元素的入栈和出栈操作。

顺序表和栈存储数据的方式高度相似,只不过栈对数据的存取过程有特殊的限制,而顺序表没有。例如,我们使用顺序表(用 a 数组表示)存储 {1,2,3,4},存储状态如图 1 所示:

顺序表存储 {1,2,3,4}

图 1 顺序表存储 {1,2,3,4}

使用栈存储结构存储 {1,2,3,4},存储状态如图 2 所示:

栈结构存储 {1,2,3,4}

图 2 栈结构存储 {1,2,3,4}

对比图 1 和图 2 不难看出,用顺序表模拟栈结构很简单,只要将数据从数组下标为 0 的位置依次存储即可。

从数组下标为 0 的模拟栈存储数据是常用的方法,从其他数组下标处存储数据也完全可以,这里只是为了方便初学者理解。

了解了顺序表模拟实现栈存储结构之后,接下来学习如何实现元素入栈和出栈的操作。

栈中存取元素,必须遵循“先进后出”的原则,因此若想将图 1 中存储的元素 1 从栈中取出,需依次先将元素 4、元素 3 和元素 2 从栈中取出,最后才能取出元素 1。

这里给出一种顺序表模拟入栈和出栈的实现思路:定义一个实时记录栈顶位置的变量(假设命名为 top),初始状态下栈内无任何元素,整个栈是"空栈",top 的值为 -1。一旦有数据元素进栈,则 top 就做 +1 操作;反之,如果数据元素出栈,top 就做 -1 操作。

顺序栈元素"入栈"

比如,还是模拟栈存储 {1,2,3,4} 的过程。最初栈是"空栈",top 的值为 -1,如图 3 所示:

空栈示意图

图 3 空栈示意图

将元素 1 入栈,默认数组下标为 0 一端表示栈底,元素 1 存储在数组 a[0] 处,同时 top 值 +1,如图 4 所示:

模拟栈存储元素 1

图 4 模拟栈存储元素 1

采用同样的方式,依次将元素 2、3 和 4 入栈,最终 top 的值变成 3,如图 5 所示:

模拟栈存储{1,2,3,4}

图 5 模拟栈存储{1,2,3,4}

因此,C 语言实现代码为:

//元素elem进栈,a为数组,top值为当前栈的栈顶位置
int push(int* a,int top,int elem){a[++top]=elem;return top;
}

代码中的 a[++top]=elem,等价于先执行 ++top,再执行 a[top]=elem。

顺序栈元素"出栈"

实际上,top 变量的设置对模拟数据的 "入栈" 操作没有帮助,它是为实现数据的 "出栈" 操作做准备的。

比如,将图 5 中的元素 2 出栈,则需要先将元素 4 和元素 3 依次出栈。需要注意的是,当有数据出栈时,要将 top 做 -1 操作。因此,元素 4 和元素 3 出栈的过程分别如图 6a) 和 6b) 所示:

数据元素出栈

图 6 数据元素出栈

元素 4 和元素 3 全部出栈后,元素 2 才能出栈。因此,使用顺序表模拟数据出栈操作的 C 语言实现代码为:

//数据元素出栈
int pop(int * a,int top){if (top == -1) {printf("空栈");return -1;}printf("弹栈元素:%d\n",a[top]);top--;return top;
}

代码中的 if 语句是为了防止用户做 "栈中已无数据却还要做出栈操作" 的错误操作。细心的读者还可能发现,出栈操作只是将 top 的值减 1,并没有像图 6 那样将出栈元素从数组中手动删除。这是因为,当有新的元素入栈后,新元素会将出栈元素覆盖掉,所以不删除出栈元素,也不会影响栈的正常使用,何必多此一举。

总结

通过学习顺序表模拟栈中数据入栈和出栈的操作,初学者完成了对顺序栈的学习,这里给出顺序栈及对数据基本操作的 C 语言完整代码:

/*
* 源自 https://xiecoding.cn/ds/
*/
#include <stdio.h>
//元素elem进栈
int push(int* a, int top, int elem) {a[++top] = elem;return top;
}
//数据元素出栈
int pop(int* a, int top) {if (top == -1) {printf("空栈");return -1;}printf("弹栈元素:%d\n", a[top]);top--;return top;
}
int main() {int a[100];int top = -1;top = push(a, top, 1);top = push(a, top, 2);top = push(a, top, 3);top = push(a, top, 4);top = pop(a, top);top = pop(a, top);top = pop(a, top);top = pop(a, top);top = pop(a, top);return 0;
}

程序输出结果为:

弹栈元素:4
弹栈元素:3
弹栈元素:2
弹栈元素:1
空栈

链栈的具体实现

是栈的一种实现方法,特指用链表实现栈存储结构。

链栈的实现思路和顺序栈类似,顺序栈是将顺序表(数组)的一端做栈底,另一端做栈顶;链栈也是如此,我们通常将链表的头部做栈顶,尾部做栈底,如图 1 所示:

链栈示意图

图 1 链栈示意图

以链表的头部做栈顶,最大的好处是:可以避免在实现元素 "入栈" 和 "出栈" 时做大量遍历链表的耗时操作。有元素入栈时,只需要将其插入到链表的头部;有元素出栈时,只需要从链表的头部依次摘取结点。

因此,链栈实际上是一个采用头插法插入或删除数据的链表。

链栈元素入栈

例如,依次将 1、2、3、4 存储到栈中,每个元素的入栈过程如图 2 所示:

链栈元素依次入栈过程示意图

图 2 链栈元素依次入栈过程示意图

C语言实现代码为:

链栈元素出栈

在图 2e) 所示链表的基础上,假设将元素 3 从栈中取出,根据"先进后出"的原则,要先将元素 4 出栈,然后元素 3 才能出栈,整个操作过程如图 3 所示:

链栈元素出栈示意图

图 3 链栈元素出栈示意图

实现栈顶元素出栈的 C 语言代码为:

//栈顶元素出链栈的实现函数
LineStack* pop(LineStack* stack) {if (stack) {//声明一个新指针指向栈顶节点LineStack* p = stack;//更新头指针stack = stack->next;printf("出栈元素:%d ", p->data);if (stack) {printf("新栈顶元素:%d\n", stack->data);}else {printf("栈已空\n");}free(p);}else {printf("栈内没有元素");return stack;}return stack;
}

代码中通过使用 if 判断语句,避免了用户执行"栈已空却还要数据出栈"错误操作。

总结

本节,通过采用头插法操作数据的单链表实现了链栈结构,这里给出链栈及基本操作的C语言完整代码:

/*
* 源自 https://xiecoding.cn/ds/
*/
#include <stdio.h>
#include <stdlib.h>
//链表中的节点结构
typedef struct lineStack {int data;struct lineStack* next;
}LineStack;
//stack为当前的链栈,a表示入栈元素
LineStack* push(LineStack* stack, int a) {//创建存储新元素的节点LineStack* line = (LineStack*)malloc(sizeof(LineStack));line->data = a;//新节点与头节点建立逻辑关系line->next = stack;//更新头指针的指向stack = line;return stack;
}//栈顶元素出链栈的实现函数
LineStack* pop(LineStack* stack) {if (stack) {//声明一个新指针指向栈顶节点LineStack* p = stack;//更新头指针stack = stack->next;printf("出栈元素:%d ", p->data);if (stack) {printf("新栈顶元素:%d\n", stack->data);}else {printf("栈已空\n");}free(p);}else {printf("栈内没有元素");return stack;}return stack;
}int main() {LineStack* stack = NULL;stack = push(stack, 1);stack = push(stack, 2);stack = push(stack, 3);stack = push(stack, 4);stack = pop(stack);stack = pop(stack);stack = pop(stack);stack = pop(stack);stack = pop(stack);return 0;
}

程序运行结果为:

弹栈元素:4 栈顶元素:3
弹栈元素:3 栈顶元素:2
弹栈元素:2 栈顶元素:1
弹栈元素:1 栈已空
栈内没有元素

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com