数据结构&算法模块总结
- (1)复杂度分析原理与方法
- (2)数组与链表原理和使用场景讲解
- (3)栈原理与应用场景讲解
- (4)队列原理与应用场景讲解
- (5)递归原理与虚拟机栈场景应用
- (6)二分查找及其应用场景
- (7) Redis有序集合跳表实现原理
1.顺序栈和链表栈
(1)顺序栈实现
①顺序栈基于数组,数组满时需要动态扩容
②代码实现
// 基于数组实现的顺序栈
public class ArrayStack {
private String[] items; // 数组
private int count; // 栈中元素个数
private int n; //栈的大小
// 初始化数组,申请一个大小为n的数组空间
public ArrayStack(int n) {
this.items = new String[n];
this.n = n;
this.count = 0;
}
// 入栈操作
public boolean push(String item) {
// 数组空间不够了,直接返回false,入栈失败。
if (count == n) return false;
// 将item放到下标为count的位置,并且count加一
items[count] = item;
++count;
return true;
}
// 出栈操作
public String pop() {
// 栈为空,则直接返回null
if (count == 0) return null;
// 返回下标为count-1的数组元素,并且栈中元素个数count减一
String tmp = items[count-1];
--count;
return tmp;
}
}
③扩容复杂度分析
(2)链表实现
逻辑原理和数组类似,直接看代码就好了。
public class StackBasedOnLinkedList {
private Node top = null;
public void push(int value) {
Node newNode = new Node(value, null);
// 判断是否栈空
if (top == null) { top = newNode; }
else { newNode.next = top; top = newNode; }
}
/** * 我用-1表示栈中没有数据。 */
public int pop() {
if (top == null) return -1;
int value = top.data;
top = top.next; return value;
}
public void printAll() {
Node p = top;
while (p != null) {
System.out.print(p.data + " ");
p = p.next;
}
System.out.println();
}
private static class Node {
private int data;
private Node next;
public Node(int data, Node next) {
this.data = data;
this.next = next;
}
public int getData() {
return data;
}
}
}
(3)数据结构中栈与内存中栈区别
①内存中的堆栈是真实存在的物理区,数据结构中的堆栈是抽象的数据存储结构。
【参考:JVM虚拟机栈和Native方法栈】
//例如main函数和add函数代码关系
main(){
int res=0;
int ret=0;
int a=1;
add(ret);
}
int add(int sum;){
int x=3;
int y=5;
....
}
这段代码中每个函数就是一个栈帧,在JVM虚拟机的内存模型如下:
本质上:栈中存放的是多个栈帧,每个栈帧对应一个被调用的方法,主要包括局部变量表、操作数栈、动态链接、方法返回地址(方法出口)。每一个方法的执行,JVM 都会创建一个栈帧,并且将栈帧压入 Java 栈,方法执行完毕,该栈帧出栈。这里不详细介绍了。
2.栈应用场景
(1)浏览器前进和后退功能模拟
在浏览器中,我们浏览页面时可以选择后退或前进。后退即返回之前浏览的页面,而前进则是在后退基础上使用,但它并不能前进到未加载过的页面。
用两个栈即可实现:
-
把首次浏览的页面依次压入栈X
-
当点击后退按钮时,再依次从栈X中出栈,并将出栈的数据依次放入栈Y。
-
当点击前进按钮时,依次从栈Y中取出数据,放入栈X中。
-
当栈X中没有数据时,那就说明没有页面可以继续后退浏览了。当栈Y中没有数据,那就说明没有页面可以点击前进按钮浏览了
(2)两个栈实现队列
将浏览器的功能再抽象化,其实可以发现就是栈模拟队列的过程。其实现思路如下:
①入队(add):每次入队,所有元素压入stack1中(此时顺序是逆序)。
②出队(remove):首先检查stack2中是否有元素,如果没有则stack1元素全部弹到stack2中(顺序还原了),然后stack2进行pop弹出顶部即可。如果stack2已经有元素直接弹出就行了。因为队列先进来的元素只会再stack1中,除非stack2空了才压进来。
③队首元素(peek):和出队一样,要检查stack2是否为空进行压入。然后stack2进行peek操作查看顶部元素即可。
④队空(empty):stack1和stack2必须全空,才表示没队列元素。
实现代码如下: