一、栈是什么?

我们首先来看我们在百度百科给出的在计算机领域的解释:

技术栈 devops 技术栈为什么叫栈_c++

单单看这些文字肯定还是不能理解,要搞清楚这个概念,首先要明白”栈“原来的意思,如此才能把握本质。"栈“者,存储货物或供旅客住宿的地方,可引申为仓库、中转站,所以引入到计算机领域里,就是指数据暂时存储的地方,所以才有进栈、出栈的说法。这时候我们用图来理解一下这段文字

技术栈 devops 技术栈为什么叫栈_技术栈 devops_02

 在这一个个“桶”中,存放的就是数据,而这个“桶”就可以理解为一个栈,其实栈就是一种将数据依次“堆叠”的一种数据组织方式。

二、栈的定义

栈(stack)是限定仅在表尾进行插入或者删除的线性表。对于栈来说,表尾端称为栈顶(top),表头端称为栈低(bottom)。不含元素的空表称为空栈。因为栈限定在表尾进行插入或者删除,所以栈又被称为后进先出的线性表(简称LIFO:Last in, First out.结构)。

技术栈 devops 技术栈为什么叫栈_技术栈 devops_03

三、 栈的应用

  在了解了什么是栈之后,我们就应该学习栈应该怎么用,而我的学习的语言是C/C++,所以先主要了解在C和C++中的简单用法。

C语言中栈的基本操作:

栈的基本操作有:栈的初始化、判空、判满、取栈顶元素、在栈顶进行插入和删除。在栈顶插入元素称为入栈,在栈顶删除元素称为出栈。

栈的初始化

栈和线性表类似,也有两种存储表示方法顺序栈和链栈,链栈的操作是线性表操作的特例,操作比较容易实现。顺序栈即栈的顺序存储结构是利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素,同时附设指针top指示栈顶元素在顺序栈中的位置,top = 0表示空栈。由于栈在使用的过程中所需要的大小难以估计,所以通常是先为栈分配一个基本容量,然后再使用的过程中,当栈的空间不够使用的时候再继续追加存储空间。我们以下述类型说明作为顺序栈的定义:

typedef struct{
	SDataType *base; //栈底指针
	SDataType *top;  //栈顶指针
	int StackSize;   //当前已经分配的存储空间,以元素为单位 
}SqStack;

==malloc()==函数来分配存储空间。base作为栈底指针,它始终指向栈底,所以s.top = s.base可以作为栈空的标记。top为栈顶指针,top的初值指向栈底。每当插入一个元素时top加1,弹出一个元素时top减1,因此,非空栈中的栈顶指针始终在栈顶元素的下一个位置上。

//初始化顺序栈,构造一个空栈
Status InitStack(SqStack &S){
	//分配存储空间 
	S.base = (SDataType *)malloc(STACK_INIT_SIZE*sizeof(SDataType));
	if(!S.base){
		//如果分配失败,则返回error 
		return OVERFLOW;
	}
	//S.top 始终指向栈顶元素的下一个位置 
	S.top = S.base;    //初始状态下为空栈 
	S.StackSize = STACK_INIT_SIZE;   //当前已经分配的存储容量为100个 
	return OK;	
}

判断是否为空栈

当我们弹出栈顶元素时,往往需要判断一下栈是否为空来防止发生下溢。上面我们说到==base作为栈底指针,它始终指向栈底,所以s.top = s.base可以作为栈空的标记。==所以我们可以这样判断栈是否为空:

//判断是否为空栈
void judgeNull(SqStack &s){
	if(s.top == s.base){
		printf("此栈为空栈!\n");
	}else{
		printf("此栈不为空栈!\n");
	}
}

判断是否为满栈

当我们使一个元素入栈的之前,我们往往需要判断一下栈是否为满栈,防止发生上溢的情况。因为我们定义了一个StackSize来表示当前已经分配的存储空间,所以我们可以用s.top - s.base 来算出当前已经使用的栈空间。所以当s.top - s.base == s.StackSize时表示已经满栈:

//判断是否为满栈
void judgeFull(SqStack &s){
	if(s.top-s.base == s.StackSize){
		printf("栈满!\n");
	}else{
		printf("栈未满!\n");
	} 
}

入栈

入栈时我们首先要判断栈是否为满栈,如果为满栈我们要首先追加存储空间,然后才能将元素入栈。realloc()函数详解请看realloc详解

//入栈
Status Push(SqStack &s,SDataType e){
	SDataType *p;
	//首先判断栈是不是满的(上溢) 
	if(s.top-s.base == s.StackSize){
		//追加空间 
		p = (SDataType *)realloc(s.base,(STACK_INIT_SIZE+STACKINCREMENT)*sizeof(SDataType));
		if(!p){
			//如果没有找到符合条件的存储空间,则返回error 
			return OVERFLOW;
		}
		//成功找到则使s.base指向p 
		s.base = p;
		s.top = s.base + s.StackSize;
		s.StackSize +=  STACKINCREMENT;
	}
	//先插入元素,然后将栈顶指针加 1 
	*(s.top) = e;
	s.top++;
	return OK;
}

出栈

出站时我们首先要判断栈是否为空栈,如果栈已经空了,则返回error.

//出栈
Status Pop(SqStack &s,SDataType &e){
	//判断是否会发生下溢 
	if(s.top != s.base){
		s.top--;    //先将栈顶指针减 1 
		e = *(s.top);
	}else{
		return 0;
	}
	return e;
}

C语言实现栈的具体代码

#include<stdio.h>
#include<malloc.h>

#define STACK_INIT_SIZE 100  //栈的初始容量 
#define STACKINCREMENT 10    //容量增量
#define OK 1 
#define OVERFLOW -2
typedef int SDataType;
typedef int Status;

typedef struct{
	SDataType *base; //栈底指针
	SDataType *top;  //栈顶指针
	int StackSize;   //当前已经分配的存储空间,以元素为单位 
}SqStack;

//初始化顺序栈,构造一个空栈
Status InitStack(SqStack &S){
	//分配存储空间 
	S.base = (SDataType *)malloc(STACK_INIT_SIZE*sizeof(SDataType));
	if(!S.base){
		//如果分配失败,则返回error 
		return OVERFLOW;
	}
	//S.top 始终指向栈顶元素的下一个位置 
	S.top = S.base;    //初始状态下为空栈 
	S.StackSize = STACK_INIT_SIZE;   //当前已经分配的存储容量为100个 
	return OK;	
} 

//入栈
Status Push(SqStack &s,SDataType e){
	SDataType *p;
	//首先判断栈是不是满的(上溢) 
	if(s.top-s.base == s.StackSize){
		//追加空间 
		p = (SDataType *)realloc(s.base,(STACK_INIT_SIZE+STACKINCREMENT)*sizeof(SDataType));
		if(!p){
			//如果没有找到符合条件的存储空间,则返回error 
			return OVERFLOW;
		}
		//成功找到则使s.base指向p 
		s.base = p;  //系统会将原来的内容复制过来
		s.top = s.base + s.StackSize;
		s.StackSize +=  STACKINCREMENT;
	}
	//先插入元素,然后使栈顶指针加 1 
	*(s.top) = e;
	s.top++;
	return OK;
} 

//出栈
Status Pop(SqStack &s,SDataType &e){
	//判断是否会发生下溢 
	if(s.top != s.base){
		s.top--;    //先将栈顶指针减 1 
		e = *(s.top);
	}else{
		return 0;
	}
	return e;
}

//判断是否为空栈 
void judgeNull(SqStack &s){
	if(s.top == s.base){
		printf("此栈为空栈!\n");
	}else{
		printf("此栈不为空栈!\n");
	}
}

//判断是否为满栈
void judgeFull(SqStack &s){
	if(s.top-s.base == s.StackSize){
		printf("栈满!\n");
	}else{
		printf("栈未满!\n");
	} 
} 

int main(){
	SqStack s;
	SDataType element;
	
	InitStack(s);  //初始化栈
	//将1-5入栈
	for(int i=1;i<=10;i++){
		Push(s,i);
	}
	
	judgeNull(s);
	judgeFull(s);
	
	printf("出栈:\n");
	//只要栈不为空 
	while(s.top != s.base){
		Pop(s,element);    //出栈的元素用e接收 
		printf("%d ",element);
	}
	
	printf("\n"); 
	judgeNull(s);
	
	return 0;
	 
}

C++实现一个栈

在做lintcode时碰到一个简单的实现栈,但是语言为C++

技术栈 devops 技术栈为什么叫栈_算法_04

题解: 

class Stack {
public:
    /*
     * @param x: An integer
     * @return: nothing
     */
    void push(int x) {
        // write your code here
        xx.push_back(x);
    }

    /*
     * @return: nothing
     */
    void pop() {
        // write your code here
        xx.pop_back();
    }

    /*
     * @return: An integer
     */
    int top() {
        // write your code here
        return xx[xx.size()-1];
    }

    /*
     * @return: True if the stack is empty
     */
    bool isEmpty() {
        // write your code here
        if(!xx.size()) return true;
        else return false;
    }
    private:
    std::vector<int>xx;
};

这道题也是很简单的一道题,在C++中用vector来实现一个栈的应用。

未完待续.......