栈的探究
来源:互联网 发布:emplace_back源码 编辑:程序博客网 时间:2024/06/17 21:04
1、栈的定义:栈是一种特殊的线性表。其特殊性在于限定插入和删除数据元素的操作只能在线性表的一端进行。栈中的数据是先进后出的(First In Last Out, FILO)。栈只有一个出口,允许新增元素(只能在栈顶上增加)、移出元素(只能移出栈顶元素)、取得栈顶元素等操作。在STL中,栈是以别的容器作为底部结构,再将接口改变,使之符合栈的特性就可以了。在STL中,栈有五种操作:top()、push()、pop()、 size()、empty() 。
top():返回栈顶的数据
push(element):在栈顶增加element元素
pop():弹出栈顶元素
size():返回栈中数据的个数
:这个模板实例化的类型参数中,前者int是实例化stack(栈)的数据类型,后者list是实现栈的配接器(adapter),也就是说是用int型的list(实际上是双向链表)来实现这个stack,因为STL中并没有单独实现的stack类型,按照STL的说法,一般不要使用list来实现,默认stack是用deque(双向队列)来实现的。
由于栈也是线性表,因此线性表的存储结构对栈也适用,通常栈有顺序栈和链栈两种存储结构,这两种存储结构的不同,则使得实现栈的基本运算的算法也有所不同。
我们要了解的是,在顺序栈中有”上溢”和”下溢”的概念。顺序栈好比一个盒子,我们在里头放了一叠书,当我们要用书的话只能从第一本开始拿,那么当我们把书本放到这个栈中超过盒子的顶部时就放不下了,这时就是”上溢”,”上溢”也就是栈顶指针指出栈的外面,显然是出错了。反之,当栈中已没有书时,我们再去拿,看看没书,把盒子拎起来看看盒底,还是没有,这就是”下溢”。”下溢”本身可以表示栈为空栈,因此可以用它来作为控制转移的条件。
链栈则没有上溢的限制,它就象是一条一头固定的链子,可以在活动的一头自由地增加链环(结点)而不会溢出,链栈不需要在头部附加头结点,因为栈都是在头部进行操作的,如果加了头结点,等于要在头结点之后的结点进行操作,反而使算法更复杂,所以只要有链表的头指针就可以了。
2、栈与堆的区别
(1)stack是有结构的,每个区块按照一定次序存放,可以明确知道每个区块的大小;heap是没有结构的,数据可以任意存放。因此,stack的寻址速度要快于heap。
(2)一般来说,每个线程分配一个stack,每个进程分配一个heap,也就是说,stack是线程独占的,heap是线程共用的。
(3)stack创建的时候,大小是确定的,数据超过这个大小,就发生stack overflow错误,而heap的大小是不确定的,需要的话可以不断增加。
所以综上所述:只要是局部的、占用空间确定的数据,一般都存放在stack里面,否则就放在heap里面。
我从网上摘取了具体代码在内存的存放方式:
上面代码的Method1方法,共包含了三个变量:i, y 和 cls1。其中,i和y的值是整数,内存占用空间是确定的,而且是局部变量,只用在Method1区块之内,不会用于区块之外。cls1也是局部变量,但是类型为指针变量,指向一个对象的实例。指针变量占用的大小是确定的,但是对象实例以目前的信息无法确知所占用的内存空间大小。
这三个变量和一个对象实例在内存中的存放方式如下。
接下来的问题是,当Method1方法运行结束,会发生什么事?
回答是整个stack被清空,i、y和cls1这三个变量消失,因为它们是局部变量,区块一旦运行结束,就没必要再存在了。而heap之中的那个对象实例继续存在,直到系统的垃圾清理机制(garbage collector)将这块内存回收。因此,一般来说,内存泄漏都发生在heap,即某些内存空间不再被使用了,却因为种种原因,没有被系统回收。
3、关于地址高低的问题
栈顶是低地址,栈底是高地址,esp指向的内存位置永远是栈顶,第一个进栈的数据是在栈底。栈区的增长方向是从高地址到低地址,也就是说栈顶的地址低于栈底
一般x86平台都是小端序,也就是高高低低,即:高位字节存放在内存高地址处,低位字节存放在低地址处。对于整型变量a=0x12345678,其内存布局为78 56 34 12
大端序一般在以太网通信中,所以又叫网络字节序,因此上面的变量a在大端序系统上就是12 34 56 78
4、栈顺序存储
代码从网上摘抄:
// Test.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <iostream> using namespace std; #define MAX 10 // MAXIMUM STACK CONTENT class stack { private: int arr[MAX]; int top; public: stack() { inItStack(); } /************************************************************************/ /* 初始化栈 */ /************************************************************************/ void inItStack() { top=-1; } /***********************************/ /* 入栈*/ /************************************/ void push(int a) { top++; if(top < MAX) { arr[top]=a; } else { cout<<"STACK FULL!!"<<top; } } /**********************************/ /* 出栈*/ /**********************************/ int pop() { if(Empty()) { cout<<"STACK IS EMPTY "; return NULL; } else { int data=arr[top]; arr[top]=NULL; top--; return data; } } /************************************************************************/ /* 是否为空 */ /************************************************************************/ bool Empty() { if(top == -1) return true; else return false; } }; int main() { stack a; a.push(3); a.push(10); a.push(1); cout<<"Pop:"<<a.pop(); return 0; }
5、栈的链式存储
若是栈中元素的数目变化范围较大或不清楚栈元素的数目,就应该考虑使用链式存储结构。人们将用链式存储结构表示的栈称作”链栈”。链栈通常用一个无头结点的单链表表示。如图所示:
代码为:
#include "stdafx.h" #include <stdio.h> #include "stdlib.h" #include <iostream> using namespace std; //宏定义 #define TRUE 1 #define FALSE 0 #define OK 1 #define ERROR 0 #define INFEASIBLE -1 #define OVERFLOW -2 #define STACKEMPTY -3 #define LT(a,b) ((a)<(b)) #define N = 100 typedef int Status; typedef int ElemType; typedef struct LNode{ ElemType data; struct LNode *next; }LNode, *LinkList; typedef struct stack{ LinkList top; } STACK; /************************************************************************/ /* 接口: */ /************************************************************************/ void InitStack(STACK &S); void Push(STACK &S,ElemType e); void Pop(STACK &S, ElemType *e); ElemType GetTop(STACK S,ElemType *e); int StackEmpty(STACK S); /************************************************************************/ /* */ /************************************************************************/ void InitStack(STACK &S) { S.top=NULL; } /************************************************************************/ /* 入栈 */ /************************************************************************/ void Push(STACK &S,ElemType e) { LinkList p; p = (LinkList )malloc(sizeof(LNode)); if (!p) exit(OVERFLOW); p->data = e; p->next = S.top; S.top = p; } /**************************/ /* 出栈 */ /*************************/ void Pop(STACK &S, ElemType *e) { LinkList p; if(StackEmpty(S)) exit(STACKEMPTY); *e = S.top->data; p = S.top; S.top = p->next; free(p); } /***************************/ /* 获取栈顶元素内容 */ /***************************/ ElemType GetTop(STACK S, ElemType *e) { if(StackEmpty(S)) exit(STACKEMPTY); *e = S.top->data; } /***************************/ /* 判断栈S是否空*/ /****************************/ int StackEmpty(STACK S) { if(S.top==NULL) return TRUE; return FALSE; } void main() { STACK S; InitStack( S); Push(S, 3); Push(S, 4); ElemType e; Pop(S,&e); cout<<"Pop elem:"<<e; }
参考大佬的博客链接:
1、http://www.ruanyifeng.com/blog/2013/11/stack.html
2、http://blog.csdn.net/hguisu/article/details/7674195
3、http://www.cnblogs.com/dwlsxj/p/Stack.html
4、http://blog.csdn.net/morewindows/article/details/6950881
- 栈的探究
- 探究的路
- 序列的值探究
- 指针引发的探究
- 探究interface的特性
- lk<sid>的探究
- panda3d attachNewNode的探究
- 关于PostQuitMessage()的探究
- 探究c的指针
- 二分模型的探究
- 探究string的应用
- va的探究
- 关于Fragment的探究
- 探究AFNetworking的使用
- 位运算 的探究
- 位运算 的探究
- 枚举类型的探究
- App的相关探究
- Kaldi-Timit 训练
- MySQL5.7 安装
- 【PB登陆的实现】
- Matlab中如何把m文件默认打开方式设成editor
- Springmvc和struts2的区别
- 栈的探究
- SpringBoot学习-(六)SpringBoot与Mybatis整合
- 【C#机房重构】用户sa失败-管道的另一端上无任何进程-无法找到表0
- win32飞机大战
- SQLAlchemy的基本使用
- 单例模式
- Matplotlib 入门(三):多图合并
- C#如何根据字符串动态的创建对象(类)
- 二分搜索树(一)