目录
1.堆
2.栈(stack):先进后出
3.堆、栈区别总结
4.队列:先进先出
5.链表实现
1.1堆通常是一个可以被看做一棵树的数组对象。堆总是满足下列性质:
将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。常见的堆有二叉堆、斐波那契堆等。
1.2堆是在程序运行时,而不是在程序编译时,申请某个大小的内存空间。即动态分配内存,对其访问和对一般内存的访问没有区别。
1.3堆是应用程序在运行的时候请求操作系统分配给自己内存,一般是申请/给予的过程。
1.4堆是指程序运行时申请的动态内存,而栈只是指一种使用堆的方法(即先进后出)。
栈也称为堆栈,是一种线性表。
栈只有一个开口,先进去的就到最底下,后进来的就在前面,要是拿出去的话,肯定是从开口端拿出去,
所以说先进后出,后进先出。
数据结构:
java实现栈(基于数组):
/**
* 栈只有一个开口,先进去的就到最底下,后进来的就在前面,要是拿出去的话,肯定是从开口端拿出去,
* 所以说先进后出,后进先出。
*/
public class MyStack {
//底层实现是一个数组
private long[] arr;
/**
* 最上层的一个指针 栈顶
*/
private int top;
/**
* 默认的构造方法
*/
public MyStack(){
arr = new long[10];
top=-1;
}
/**
* 增加数据 先把指针加一
* 然后指针指向最新的数据
*/
public void push(int value){
//top++是top先不自加,在语句完后自加。| ++top先自加 然后使用top的值
arr[++top] = value;
}
/**
* 移除数据 先把最顶层指针执行的数据return 然后指针减一
*/
public long pop(){
//--top 是先执行top=top-1,然后再使用top的值 | top-- 是先使用top的值 然后 在执行top=top-1
return arr[top--];
}
public static void main(String[] args) {
MyStack myStack = new MyStack();
myStack.push(1);
myStack.push(2);
myStack.push(3);
System.out.println(myStack.pop());
}
}
main()方法中 3 是最后push()进去 是最先pop()出来,先进后出,后进先出。
1.堆栈空间分配
①栈(操作系统):由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
②堆(操作系统): 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表。
2.堆栈缓存方式
①栈使用的是一级缓存, 他们通常都是被调用时处于存储空间中,调用完毕立即释放。
②堆则是存放在二级缓存中,生命周期由虚拟机的垃圾回收算法来决定(并不是一旦成为孤儿对象就能被回收)。所以调用这些对象的速度要相对来得低一些。
3.堆栈数据结构区别
①堆(数据结构):堆可以被看成是一棵树,如:堆排序。
②栈(数据结构):一种先进后出的数据结构。
①队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。
②队列中没有元素时,称为空队列。
③建立顺序队列结构必须为其静态分配或动态申请一片连续的存储空间,并设置两个指针进行管理。一个是队头指针front,它指向队头元素;另一个是队尾指针rear,它指向下一个入队元素的存储位置。
④队列采用的FIFO(first in first out),新元素(等待进入队列的元素)总是被插入到链表的尾部,而读取的时候总是从链表的头部开始读取。每次读取一个元素,释放一个元素。所谓的动态创建,动态释放。因而也不存在溢出等问题。由于链表由结构体间接而成,遍历也方便。(先进先出)
队列的数据结构
java实现队列(基于数组)
package javaee.net.cn.tree.ch10;
public class MyQueue {
//底层使用数组
private long[] arr;
//队头
private int front;
//队尾
private int end;
/**
* 默认构造方法
*/
public MyQueue(){
arr = new long[10];
front=0;
end = -1;
}
/**
* 添加数据 从队尾插入
*/
public void insert(long value){
arr[++end] = value;
}
/**
* 删除数据,从队头删除
*/
public long remove(){
return arr[front++];
}
public static void main(String[] args) {
MyQueue myQueue = new MyQueue();
myQueue.insert(1L);
myQueue.insert(2L);
System.out.println(myQueue.remove());
}
}
main()方法中 1 是先insert()进去 也是先remove()出来,所以说 先进先出。
以上队列是以数组来模拟(比较简单),JDK API中的Queue队列底层是以链表来实现的。
LinkedList 类实现了Deque(双端队列)接口 并且具有
addFirst() addLast() getFirst() getLast() removeFirst() removeLast() 方法
使得LinkList可以作为 栈 队列 双向队列使用
上面的栈和队列都是以数组模拟实现,但是JDK中LinkedList底层是链表实现的,现在我们看看什么是链表
链表是由一个个的节点构成的,节点(Node)分为两个部分,第一个部分(data)保存或者显示关于节点的信息,另一个部分存储下一个节点的地址。
链表最后一个节点存储地址的部分指向空值。
节点Node:
/**
* 连接点 相当于是车厢
*/
public class Node {
//数据域 保存数据
public long data;
//指针域 保存下一个节点的引用
public Node next;
public Node(long value){
this.data=value;
}
}
而插入一个节点,对于单向链表,我们只提供在链表头插入,只需要将next指向原头节点,当前插入的节点设置为头节点即可。
/**
* 插入一个节点,在头结点进行插入
*/
public void insertFirst(long value){
Node node = new Node(value);
node.next=first;
first=node;
}
删除一个节点,我们将该节点的上一个节点的next指向该节点的下一个节点。
如果被删除的是头结点,直接将头节点的下一个节点,赋值给头节点
/**
* 删除方法 根据数据域进行删除
*/
public Node delete(long value){
Node current = first;
Node pre = null;
while(current.data!=value){
if(current.next==null){
return null;
}
pre = current;
current= current.next;
}
if(current == first){
first = first.next;
}else{
pre.next=current.next;
}
return current;
}