【数据结构 三】---栈
来源:互联网 发布:在线随机抽签软件 编辑:程序博客网 时间:2024/05/30 05:08
在学习的过程中有时会遇到一种数据结构也就是栈,这里对栈做个详细的了解。在完善这篇博客的过程中主要参考了这两篇博文:http://www.cnblogs.com/QG-whz/p/5170418.html#_label1_1和http://blog.csdn.net/javazejian/article/details/53362993在这里注明出处,所涉及到的代码皆由我用java实现。第一次修改日期是2017.8.02下午
栈简介
栈的特点
栈(Stack)是一种线性存储结构,也可以称做一种操作受限的特殊的线性表,其插入和删除操作只允许在线性表的一端进行,一般而言,把允许操作的一端称为栈顶(Top),不可操作的一端称为栈底(Bottom),栈顶也就是线性序列的末端。
总结有如下两个特点:
1, 栈中的数据元素遵守”后进先出”( Last In Out First)的原则,简称LIFO结构。
2, 限定只能在栈顶进行插入和删除操作。
栈的相关概念
1,栈顶与栈底:允许元素插入与删除的一端称为栈顶(TOP),另一端称为栈底(BOTTOM)。
2,压栈:栈的插入操作,叫做进栈,也称压栈、入栈(PUSH)。
3,弹栈:栈的删除操作,也叫做出栈(POP)。
栈的基本运算
1,入栈(push)
在压栈的过程中,栈顶的位置一直在”向上“移动,而栈底是固定不变的。
2,出栈(pop)
出栈的顺序为3、2、1 ,顺序与入栈时相反,这就是所谓的”后入先出“。
在弹栈的过程中,栈顶位置一直在”向下“移动,而栈底一直保持不变。
3,求栈的大小(size)
4,判断栈是否为空(isEmpty)
5,获取栈顶元素的值(top)
栈的实现方式
java中Stack类的使用
/** * Stack类 * 栈:桶型或箱型数据类型,后进先出,相对堆Heap为二叉树类型,可以快速定位并操作 * Stack<E>,支持泛型 * public class Stack<E> extends Vector<E> * Stack的方法调用的Vector的方法,被synchronized修饰,为线程安全(Vector也是) * Stack methods: * push : 把项压入堆栈顶部 ,并作为此函数的值返回该对象 * pop : 移除堆栈顶部的对象,并作为此函数的值返回该对象 * peek : 查看堆栈顶部的对象,,并作为此函数的值返回该对象,但不从堆栈中移除它 * empty : 测试堆栈是否为空 * search : 返回对象在堆栈中的位置,以 1 为基数 * size:返回栈的大小 * */
package ca.map; import java.util.Stack; public class StackX { public static void main(String[] args) { stackMethod(); } //stack operate public static void stackMethod(){ //定义一个Integer泛型的Stack Stack<Integer> stack = new Stack<Integer>(); System.out.println("新建栈stack是否为空 : "+(stack.empty() ? "空" : stack.size())); //push : 把项压入堆栈顶部,返回值泛型指定的类型 //此处将1到5压入栈中 stack.push(1); stack.push(2); stack.push(3); stack.push(4); stack.push(5); System.out.println("将1到5按顺序压入栈中后为:"+stack); //empty : 测试堆栈是否为空,size() == 0,返回值boolean System.out.println("值为1~5的栈中stack是否为空 : "+(stack.empty() ? "空" : stack.size())); //search : 返回对象在堆栈中的位置,以 1 为基数,参数:search(Object o) ,返回值int int oStack = stack.search(3); System.out.println("查找栈stack中对象3的位置elementId为 : "+oStack); //peek : 查看堆栈顶部的对象,但不从堆栈中移除它,返回值泛型指定的类型 int topElement =stack.peek(); System.out.println("查看stack的栈顶元素为 : "+topElement); System.out.println("peek操作stack后为 : "+stack); //pop : 移除堆栈顶部的对象,并作为此函数的值返回该对象,返回值泛型指定的类型 int oRemove = stack.pop(); System.out.println("移除stack栈顶的元素为 : "+oRemove); System.out.println("pop操作移除stack栈顶元素后为 : "+stack); } }
测试结果
新建栈stack是否为空 : 空将1到5按顺序压入栈中后为:[1, 2, 3, 4, 5]值为1~5的栈中stack是否为空 : 5查找栈stack中对象3的位置elementId为 : 3查看stack的栈顶元素为 : 5peek操作stack后为 : [1, 2, 3, 4, 5]移除stack栈顶的元素为 : 5pop操作移除stack栈顶元素后为 : [1, 2, 3, 4]
若集合为空,返回 []
若集合不为空则 [ 加上迭代元素 加上 , 最后集合无元素加上 ] eg:[1, 2, 3, 4]
栈按照存储结构有两种实现方式。
数组实现
栈的创建和常用方法代码:
package stack;import java.util.EmptyStackException;public class MyStackArray<T> { public T[] array = null; // 存放元素的数组 public int initalSize = 5; // 栈的容量大小,默认为10 public int top = -1; // 栈顶指针 ,-1表示空栈,因为数组下标从0开始。 public int curSize; //表示栈的当前实际容量是多大 public MyStackArray() { this(5); } @SuppressWarnings("unchecked") public MyStackArray(int Size) { // 构造函数,用于初始化栈大小 if (Size >= 0) { this.initalSize= Size; // 栈的容量为该值 array = (T[]) new Object[Size]; // 存放栈元素数组大小的值也为该值 top = -1; // 如果栈顶指针指向-1,表示空栈, curSize = 0; } else { throw new RuntimeException("初始化大小不能小于0:" + Size); } } // 判断该栈是否为空 public boolean isEmpty() { return top == -1 ? true : false; // 如果栈顶指针指向-1,表示空栈 } // 扩充栈的的容量 @SuppressWarnings("unchecked") public void expandCapacity() { // 如果需要拓展的容量比现在数组的容量还小,则无需扩容 T[] old = array; array = (T[]) new Object[curSize * 2 + 1]; initalSize = curSize * 2 + 1; // 复制元素 for (int i = 0; i < top; i++) array[i] = old[i]; } // 进栈,先判断栈是否已经满了 public void push(T data) { if (top == initalSize-1) { expandCapacity(); // 如果栈已经满了,则扩充容量 } // 从栈顶添加元素 array[++top] = data; // 没满的话top指向的下一个元素为该元素,数组扩充 curSize++; } // 出栈,首先判断是否为空栈,为空则报异常 public T pop() { if (isEmpty()) new EmptyStackException(); curSize--; return array[top--]; // 返回要删除的元素 } // 查看栈顶元素但不移除 public T peek() { if (isEmpty()) new EmptyStackException(); return array[top]; } //返回对象在堆栈中的位置,以 1 为基数 public int search(T data){ int i = top; while(top != -1){ if(peek() != data){ top--; }else{ break; } } int result = top+1; top = i; //top返回栈顶位置 return result; }}
测试代码:
package stack;public class Stack { public static void main(String[] args) { MyStackArray<Integer> s = new MyStackArray<Integer>(); s.push(1); s.push(5); s.push(3); s.push(4); System.out.println("栈的容量"+ s.initalSize); System.out.println("栈顶元素"+s.peek()); System.out.println("搜索元素的位置" +s.search(5)); System.out.println("出栈元素是"+s.pop()); System.out.println("出栈一次后栈顶" +s.peek()); s.push(8); s.push(9); System.out.println("栈顶元素"+s.peek()); System.out.println("栈的容量"+ s.initalSize); s.push(10); System.out.println("栈顶元素"+s.peek()); System.out.println("栈的容量"+ s.initalSize); }}
测试结果
栈的容量5栈顶元素4搜索元素的位置2出栈元素是4出栈一次后栈顶3栈顶元素9栈的容量5 //注意,在这个地方由于增加元素超过总容量,所以自动扩容栈顶元素10栈的容量11
单链表实现
链表类代码
package stack;public class Node<T> { public T val; public Node<T> next = null; public Node(T val, Node<T> next) { //构造方法,创建一个新节点 this.val = val; this.next = next; }}
单链表组成的栈代码
package stack;public class MyStackList<T> { public Node<T> top; // 栈顶元素 public int curSize; // 判断该栈是否为空 public boolean isEmpty() { return curSize == 0 ? true : false; } // 进栈,先判断栈是否已经满了 public void push(T val) { if (val == null) { System.out.println("新加节点的数据不能为null"); } if (top == null) { top = new Node<T>(val, null); // 如果当前为空栈,无节点,则进来的节点为第一个节点 } else if (top.val == null) { top.val = val; // 如果当前top不为null,但是其中的数据为null,则只需把当前的数据赋给栈顶就好 } else { Node<T> newNode = new Node<T>(val, top); top = newNode; // 更新栈顶 } curSize++; } // 出栈,首先判断是否为空栈,为空则报异常 public T pop() { if (isEmpty()) { System.out.println("栈为空"); } T oldData = top.val; top = top.next; curSize--; return oldData; } // 查看栈顶元素但不移除 public T peek() { if (isEmpty()) { System.out.println("栈为空"); } return top.val; } // 返回对象在堆栈中的位置,以 1 为基数 public int search(T data) { int count = curSize; Node<T> temp = top; while (temp != null) { if (temp.val == data) return count; count--; temp = temp.next; } return -100000; }}
测试代码
package stack;public class ListStack { public static void main(String[] args) { MyStackList<Integer> s = new MyStackList<Integer>(); s.push(1); s.push(5); s.push(3); s.push(3); System.out.println("栈的容量"+ s.curSize); s.pop(); System.out.println("栈的容量"+ s.curSize); System.out.println("栈顶元素"+s.peek()); System.out.println("搜索元素的位置" +s.search(1)); System.out.println("出栈元素是"+s.pop()); System.out.println("出栈两次后栈顶" +s.peek()); s.push(8); s.push(9); System.out.println("栈顶元素"+s.peek()); System.out.println("栈的容量"+ s.curSize); s.push(10); System.out.println("栈顶元素"+s.peek()); System.out.println("栈的容量"+ s.curSize); }}
测试结果
栈的容量4栈的容量3栈顶元素3搜索元素的位置1出栈元素是3出栈两次后栈顶5栈顶元素9栈的容量4栈顶元素10栈的容量5
两种实现的时间复杂度比较
顺序栈复杂度如下:
链式栈复杂度如下:
由此可知栈的主要操作都可以在常数时间内完成,这主要是因为栈只对一端进行操作,而且操作的只是栈顶元素。
LinkedList实现栈
import java.util.LinkedList;/** * 基于LinkedList实现栈 * 在LinkedList实力中只选择部分基于栈实现的接口 */public class StackList<E> { private LinkedList<E> ll = new LinkedList<E>(); //入栈 public void push(E e){ ll.addFirst(e); } //查看栈顶元素但不移除 public E peek(){ return ll.getFirst(); } //出栈 public E pop(){ return ll.removeFirst(); } //判空 public boolean empty(){ return ll.isEmpty(); } //打印栈元素 public String toString(){ return ll.toString(); }}
- 数据结构学习三 栈
- 数据结构:(三)栈
- 【数据结构 三】---栈
- 【数据结构 三】---栈
- 数据结构之栈(三)
- (三)数据结构
- 数据结构(三)
- 数据结构(三)栈和队列--栈
- 数据结构三栈的顺序存储结构
- <数据结构>栈的应用三:迷宫问题
- 郝斌数据结构(三):动态栈
- 《数据结构》实验三: 栈和队列
- 《数据结构》实验三: 栈和队列实验
- 《数据结构》实验三: 栈和队列实验
- 《数据结构》实验三:栈和队列实验
- 《数据结构》实验三: 栈和队列实验
- 《数据结构》实验三: 栈和队列实验
- 《数据结构》实验三:栈和队列实验
- robotframework 下拉框值的选择和筛选结果数量统计
- 多项式相乘(conv.cpp)
- STL中的random_shuffle()方法的使用
- oracle中写java代码,并调用.
- Spring IOC+AOP原理
- 【数据结构 三】---栈
- Hdu 6058 Kanade's sum【思维+链表模拟】
- 怎么给视频添加电影的古老效果?
- hihocoder1066-并查集
- 学习笔记
- HDOJ 1856 More is better (并查集 + 压缩路径 + 结点深度)
- lightGBM原理、改进简述
- 串结构练习——字符串连接(串)
- 玩出花的职责链模式