目录
一、栈的基本知识
1.栈的概念
2.栈的功能
3.栈的实现
二、栈的代码实现
1.栈的基本属性与方法
2.栈的遍历
3.入栈实现
4.出栈实现
5.数据测试
6.完整的程序代码
总结
一、栈的基本知识
1.栈的概念
根据百度百科,我们知道“栈”是存储货物或供旅客住宿的地方,可引申为仓库、中转站,所以引入到计算机领域里,栈就是数据暂时存储的地方,当栈中没有数据元素时叫做空栈。
栈(stack),是一种运算受限的线性表,限定只在表尾进行插入和删除操作,插入删除这一端就叫栈顶,另一端就叫栈底,总结一下就是“栈底固定,栈顶浮动”。
而正因为栈运算受限,只能在栈顶进行插入删除操作,所以栈是一种先进后出(后进先出)的数据结构。
2.栈的功能
栈的主要功能有push(入栈)、pop(出栈)、peek(获取栈顶元素,但不删除)、empty(判断栈是否为空)等,这里我们重点讨论入栈和出栈。
入栈:即向一个栈插入新元素,把新元素放到原栈顶元素的上面,使之成为新的栈顶元素。
出栈:即从一个栈中删除元素,把原栈顶元素删除,使其相邻的元素成为新的栈顶元素。
为了更好地理解栈的基本概念与入栈出栈,下面用图进行说明:
3.栈的实现
因为栈存储的是相同类型的数据,所以栈的实现有两种,一种是顺序栈,底层为数组;另一种是链式栈,利用链表实现。今天我们主要通过数组(顺序表)来完成栈的实现。
二、栈的代码实现
1.栈的基本属性与方法
有了前几天顺序表和链表的相关基础,创建栈的基本属性和方法就可以很快完成,代码如下:
public class CharStack {
	/**
	 * The depth.
	 */
	public static final int MAX_DEPTH = 10;
	
	/**
	 * The actual depth.
	 */
	int depth;
	
	/**
	 * The data.
	 */
	char[] data;
	
	/**
	 *********************
	 * Construct an empty char stack.
	 *********************
	 */
	public CharStack() {
		depth = 0;
		data = new char[MAX_DEPTH];
	} // of the first constructor这里我们同样利用final关键字来定义栈的最大长度MAX_DEPTH = 10,然后定义成员变量(depth、data),再利用new关键字为data分配内存空间。
2.栈的遍历
栈的遍历同样可以通过重写toString()方法来实现,大体结构上与顺序表、链表差不多,只是循环的时候,要注意由于栈是在栈顶这一端进行插入删除操作,所以为了便于后续入栈和出栈,我们将栈顶端对应数组的最右端(下标最大处),代码如下:
    /**
	 *********************
	 * Overrides the method claimed in Object, the superclass of any class.
	 *********************
	 */
	public String toString() {
		String resultString = "";
		
		for (int i = 0; i < depth; i++) {
			resultString += data[i];
		} // of for i
		
		return resultString;
	} // of toString3.入栈实现
和顺序表、链表一样,在入栈之前,我们显然需要先考虑此栈是否已满,对于这个问题,一样的套路,直接利用if语句进行判断:
- 如果此时栈的长度depth = MAX_DEPTH,那么就输出Stack full.,提示此栈已满。
- 如果此时栈的长度未达到MAX_DEPTH,说明栈还未满,直接将插入元素令为新的栈顶元素即可完成入栈。我们知道在插入前,原栈顶元素的下标为depth - 1(因为栈底从0开始索引),那么显然新栈顶元素的下标应在此基础上加1,所以data[depth] = paraChar;,最后不要忘了把栈的实际长度depth增加1(因为插入了一个新元素)。
    /**
	 *********************
	 * Push an element.
	 * 
	 * @param paraChar The given char.
	 * @return Success or not.
	 *********************
	 */
	public boolean push(char paraChar) {
		if (depth == MAX_DEPTH) {
			System.out.println("Stack full.");
			return false;
		} // of if
		
		data[depth] = paraChar;
		depth++;
		
		return true;
	} // of push4.出栈实现
顺序表、链表执行删除操作之前需要先判断是否为空表,类似的,在执行出栈操作之前,也需要先判断栈是否为空,这里仍然用的是if语句进行判断,并将'\0'作为返回值。
出栈其实就是删除栈顶元素,也就是删除栈最上面的元素(数组最右边的元素),所以直接将栈的长度depth减少1即可,不过,在此之前还是需要将要删除的栈顶元素赋给resultChar并返回。
    /**
	 *********************
	 * Pop an element.
	 * 
	 * @return The popped char.
	 *********************
	 */
	public char pop() {
		if(depth == 0) {
			System.out.println("Nothing to pop.");
			return '\0';
		} // of if
		
		char resultChar = data[depth - 1];
		depth--;
		
		return resultChar;
	} // of pop5.数据测试
接下来我们照例进行数据测试:
    /**
	 *********************
	 *The entrance of the program.
	 *
	 * @param args Not used now.
	 *********************
	 */
	public static void main(String[] args) {
		CharStack tempStack = new CharStack();
		
		for(char ch = 'a'; ch < 'm'; ch++) {
			tempStack.push(ch);
			System.out.println("The current stack is: " + tempStack);
		} // of for ch
		
		char tempChar;
		for(int i = 0; i < 12; i++) {
			tempChar = tempStack.pop();
			System.out.println("Popped: " + tempChar);
			System.out.println("The current stack is: " + tempStack);
		} // of for i
	} // of main6.完整的程序代码
package datastructure;
/**
 *Char stack. I do not use Stack because it is already defined in Java.
 *
 *@auther Xin Lin 3101540094@qq.com.
 */
public class CharStack {
	/**
	 * The depth.
	 */
	public static final int MAX_DEPTH = 10;
	
	/**
	 * The actual depth.
	 */
	int depth;
	
	/**
	 * The data.
	 */
	char[] data;
	
	/**
	 *********************
	 * Construct an empty char stack.
	 *********************
	 */
	public CharStack() {
		depth = 0;
		data = new char[MAX_DEPTH];
	} // of the first constructor
	
	/**
	 *********************
	 * Overrides the method claimed in Object, the superclass of any class.
	 *********************
	 */
	public String toString() {
		String resultString = "";
		
		for (int i = 0; i < depth; i++) {
			resultString += data[i];
		} // of for i
		
		return resultString;
	} // of toString
	
	/**
	 *********************
	 * Push an element.
	 * 
	 * @param paraChar The given char.
	 * @return Success or not.
	 *********************
	 */
	public boolean push(char paraChar) {
		if (depth == MAX_DEPTH) {
			System.out.println("Stack full.");
			return false;
		} // of if
		
		data[depth] = paraChar;
		depth++;
		
		return true;
	} // of push
	
	/**
	 *********************
	 * Pop an element.
	 * 
	 * @return The popped char.
	 *********************
	 */
	public char pop() {
		if(depth == 0) {
			System.out.println("Nothing to pop.");
			return '\0';
		} // of if
		
		char resultChar = data[depth - 1];
		depth--;
		
		return resultChar;
	} // of pop
	
	/**
	 *********************
	 *The entrance of the program.
	 *
	 * @param args Not used now.
	 *********************
	 */
	public static void main(String[] args) {
		CharStack tempStack = new CharStack();
		
		for(char ch = 'a'; ch < 'm'; ch++) {
			tempStack.push(ch);
			System.out.println("The current stack is: " + tempStack);
		} // of for ch
		
		char tempChar;
		for(int i = 0; i < 12; i++) {
			tempChar = tempStack.pop();
			System.out.println("Popped: " + tempChar);
			System.out.println("The current stack is: " + tempStack);
		} // of for i
	} // of main
} // of class CharStack
运行结果:

入栈时:测试的数据是从'a'到'm'之前(即从'a'到'l'这12个数据元素) ,但是在程序最开始我们就已经规定了栈的最大长度为10,所以不用说,当执行入栈操作时,最后'k'、'l'这两个数据元素必然没办法完成入栈。
出栈时:我们设置了for循环的次数为12次,即需要执行12次出栈操作,但是此时栈中只有'a'~'j'这10个数据元素,所以最后两次出栈时Nothing to pop.
总结
总的来说,今天的代码还是比较容易的,一方面是因为有了前两天顺序表和链表的基础,另一方面是因为栈的操作本身就不复杂,而且入栈出栈的时间复杂度均为O(1),所以利用栈来存取数据是比较迅速的。不过,栈虽然操作不复杂,但是它在计算机领域却有着举足轻重的作用,栈不仅是一种高效的内存结构,还贡献于计算机底层技术(例如函数调用、中断处理、程序调试等)。




















