目录
关于数据结构的简单介绍
线性结构
线性结构属于一种有序的数据元素集合,存在一一对应的线性关系,并且线性结构中只能存储相同类型的数据。类似于小朋友手拉手,对于中间的元素来说前一元素叫做前趋,后一元素叫做后继。常用的线性结构有:线性表,栈,队列,双队列,数组,串。
非线性结构
没有线性结构那样的性质。一个元素可以对应多个节点,与之对应的前者都叫做前趋,后续的节点都叫后继。常见的非线性结构有:二维数组,多维数组,广义表,树(二叉树等)。
栈
栈是一种限制了插入和删除只能在末端进行的线性表。末端操作位置称为栈顶(top),不允许操作的位置成为栈底(bottom)。插入数据的操作称之为压栈(push),取出(弹出)数据的操作叫做弹栈(出栈,pop)。由于栈的原理是表,也就意味着任何实现表的方法都可以在栈上实现。栈的时间复杂度为O(n),其他操作均为O(1)
栈的主要实现方式为链表或者数组。 使用数组实现的栈称为静态栈,使用单链表实现的栈称为动态栈。
Java中由于开发人员的疏忽,使stack继承了vector成为父子关系而不是组合关系,导致stack变成了一种糟糕的设计(相关内容可以自行查阅),从此在Java中开发人员并不推荐使用stack作为栈来存储数据,但后续版本中开发人员在Java文档中推荐使用Deque(双端队列)来实现栈,而Deque可以在两头进行数据操作,和原始的栈还是相差甚远,可以对Deque接口进行实现,创建自己的栈,使一端无法被操作从而实现栈的功能。
栈的运行方式
栈的实现方式
使用数组实现栈
- 首先定义一个数组用于存储数据,数组长度固定
- 定义top表示栈顶,初始化数据为-1
- 入栈时,数据存入,top++
- 出栈时,数据删除,top--
代码实现
public class StackModel {
/** 定义栈内存 */
private int stack[];
/** 栈顶 初始化为 -1*/
private int top =-1;
/**
* 初始化数组
* @param i
*/
public StackModel(int i) {
stack = new int[i];
}
/**
* 数据入栈
* @param i
*/
public void push(int i) {
top++;
stack[top]=i;
}
public void pop() {
stack[top]=0;
top--;
}
public void query() {
if(top==-1) {
return;
}
for(int i=0;i<=top;i++) {
System.out.println(stack[i]);
}
}
}
栈的应用场景
Java子程序的调用
为了有效的防止栈溢出,在循环遍历的时候,我们必须在循环条件中加入停止条件,不能使程序进入死循环,当然递归也是如此
处理递归调用
和子程序调用一样,只不过在入栈时,不仅记录了方法,还记录了一些参数
中缀表达式转换成后缀表达式(逆波兰表达式)
我们正常人类习惯的计算方式1+2*3(这样的表达式为中缀表达式)而计算机无法识别这样的表达式,因为计算机只能按照顺序依次进行计算,但要想在计算过程中体现出优先级,就必须把这样的中缀表达式变成另外一种表达式,即后缀表达式。
中缀表达式 后缀表达式 1+2 12+ 1+2*3 123*+ (1+2)*3 123+* 以表格中第二列为例子,在中缀表达式转后缀表达式时,需要数字栈和符号栈。由于栈插入数据的特点是先入后出,所以当1+2*3时,1最先入栈,会被放在最下面,其次2再入栈,再到3。而符号栈中,*的优先级大于+所以*号先入栈,此时将2和3弹栈相乘再入栈,再将+号入栈时,取出1和6(由2*3得来)进行相加
二叉树的遍历
以上图为例,绿色箭头为入栈,红色箭头为出栈。当我们需要在二叉树中遍历时,从根节点7开始出发, 来到左节点,将左节点的5记录在栈中,再前往右节点,将右节点的6记录在栈中。最终输出需要查找的元素6。其余元素的获取方法都是如此。
图形深度优先搜索法
和二叉树的遍历一致,在遍历时会记录在栈中。
这个系列的博客都是我在学习数据结构和算法中,我个人的一些看法和见解,欢迎各位大佬指正