【51CTO.com原创稿件】小妖毕业于重庆邮电大学计算机系,目前是一枚小小Android移动应用开发程序员,爱生活,爱女朋友,没事的时候还爱玩儿游戏,爱死磕。目前人生目标:赚钱买房买车娶媳妇儿。
小妖·Android开发
栈和队列介绍
学过计算机编程基础的朋友都知道计算机中最常见的数据结构栈和队列,这种线性表结构之所以很常见,正是因为它们简单却强大的功能特性是很多算法的基础构成。大三时小妖在北京一次实习面试中,面试官问过他一个问题,“怎么样用栈来实现一个队列?”当时他陷入了一个误区,认为面试官说的栈是指一个栈,由于栈的先入后出的特性,所以一个栈来完成队列的功能在概念上是不可能的。俗话说,一个栈不行,那就两个栈。OK,答对了,确实是至少需要两个栈。言归正传,既然栈和队列的应用如此广泛,那么怎么通过代码来实现他们呢?很多童鞋可能会说,这还不简单么?用集合或者数组,so easy!那么,如果为了提高执行效率,不允许使用集合或者数组呢?下面,就由小妖来为大家小小的剖析一下吧!
链式存储栈分析
栈的概念,这里就不再多说了,不清楚的童鞋请自行百度。其先入后出的特性确实有很多的实现方式。如题,我们这里将实现链式存储,何为链式存储呢?如下图:
链式存储的基本单位是Node(结点),在一个结点中,分为数据区和指针域,通过指针域指向下一个结点来将各个结点相连接。由于链式的特性,插入和删除链中的某一个结点(除链头和尾之外的其他结点)相对而言是消耗比较大的,但是用来实现栈或者队列是极好的。对于栈结构来说,数据的入栈和出栈以及判断是否到达栈底等方法是必不可少的。
代码实现
接下来看看如何用Java代码实现:
- /**
- * Created by lxh on 2017/8/1.
- * QQ-632671653
- * 自定义链式存储栈
- */
- public class LinkStack<T> {
- private Node<T> top = new Node<>();//初始化栈顶结点
- /**
- * 数据入栈操作
- * @param data
- */
- public void push(T data) {
- top = new Node<>(data, top);
- System.out.println(top.toString());
- }
- /**
- * 数据出栈操作
- * @return
- */
- public T pop() {
- T result = top.data;
- if (top.hasNext()) {
- top = top.next;
- }
- return result;
- }
- //使用内部类构建结点
- private class Node<T> {
- T data; //使用泛型来定义数据域
- Node<T> next; //定义下一个结点
- /**
- * 无参构造方法中初始化栈底部,为栈添加末端哨兵
- */
- Node() {
- data = null;
- next = null;
- }
- /**
- * 通过带参构造方法来构造每一个添加的结点对象
- * @param data
- * @param next
- */
- public Node(T data, Node<T> next) {
- this.data = data;
- this.next = next;
- }
- /**
- * 判断是否到达栈底
- * @return
- */
- boolean hasNext() {
- return data != null && next != null;
- }
- @Override
- public String toString() {
- return "Node{" +
- "data=" + data +
- ", next=" + next +
- '}';
- }
- }
- }
从代码中可以看到,在这里使用了泛型来保证入栈数据类型的通用,结点采用了内部类的方式来构造,因为其私有性,所以是可以保证数据安全的。基础不太好的同学可能会比较懵逼,不太明白这个链式是链到哪里的,所以小妖在入栈操作时将栈内信息打印了出来,相信各位一看就明白了。如下图:
【写在***】
同行中流传着这样一句话:不要重复的造轮子。但是小妖觉得,即便不需要你去造轮子,但是你也得明白轮子到底是怎样造出来。如果你只会调用API,那么你将失去竞争力。
如果你也愿意分享你的故事,请加51CTO开发者QQ交流群 542270018联系群主小官,期待你精彩的故事!
【51CTO原创稿件,合作站点转载请注明原文作者和出处为51CTO.com】