普通队列:先进先出
优先队列:出队顺序和入队顺序无关,和优先级相关
堆
二叉堆
二叉堆是一棵完全二叉树(空缺的位置在右下角)
堆中某个节点的值总是不大于其父节点的值(根节点数值最大)
数组存储二叉堆
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|
- | 62 | 41 | 30 | 28 | 16 | 22 | 13 | 19 | 17 | 15 |
parent(i)=i/2
left child(i) = 2*i
right child(i) = 2*i+1
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
62 | 41 | 30 | 28 | 16 | 22 | 13 | 19 | 17 | 15 |
parent(i)=(i-1)/2
left child(i) = 2*i+1
right child(i) = 2*i+2
package heap;
import java.util.Random;
public class MaxHeap<E extends Comparable<E>> {
public Array<E> data;
public MaxHeap(int capacity) {
data = new Array<>(capacity);
}
public MaxHeap() {
data = new Array<>();
}
//返回堆中的元素个数
public int size() {
return data.getSize();
}
//返回布尔值,表示堆中是否为空
public boolean isEmpty() {
return data.isEmpty();
}
//返回完全二叉树的数组表示中,一个索引所表示的元素的父亲节点的索引
private int parent(int index) {
if (index == 0) {
throw new IllegalArgumentException("index-0 doesn't have parent");
}
return (index - 1) / 2;
}
//返回完全二叉树的数组表示中,一个索引所表示的元素的左孩子节点的索引
private int leftChild(int index) {
return index * 2 + 1;
}
//返回完全二叉树的数组表示中,一个索引所表示的元素的右孩子节点的索引
private int rightChild(int index) {
return index * 2 + 2;
}
//向堆中添加元素 ,在数组尾部添加,如果比父节点大,则互换位置,依次类推
public void add(E e) {
data.addLast(e);
siftUp(data.getSize() - 1);
}
private void siftUp(int k) {
while (k > 0 && data.get(parent(k)).compareTo(data.get(k)) < 0) {
data.swap(k, parent(k));
k = parent(k);
}
}
//看堆中最大的是谁
public E findMax() {
if (data.getSize() == 0)
throw new IllegalArgumentException("Can not findMax when heap is empty");
return data.get(0);
}
//向堆中取出元素(最大元素)把最后一个元素补充到堆顶,和孩子中最大的元素互换位置
public E extractMax() {
E ret = findMax();
data.swap(0, data.getSize() - 1);
data.removeLast();
shifDown(0);
return ret;
}
private void shifDown(int k) {
//有左孩子
while (leftChild(k) < data.getSize()) {
int j = leftChild(k);
//有右孩子,并且右孩子比左孩子大
if (j + 1 < data.getSize() && data.get(j + 1).compareTo(data.get(j)) > 0) {
j = rightChild(k);
//data[j]是leftChild和rightChild中的最大值
if (data.get(k).compareTo(data.get(j)) >= 0)
break;
data.swap(k, j);
k = j;
}
}
}
public static void main(String[] args) {
int n = 100;
MaxHeap<Integer> maxHeap = new MaxHeap<>();
Random random = new Random();
for (int i = 0; i < n; i++) {
maxHeap.add(random.nextInt(Integer.MAX_VALUE));
}
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = maxHeap.extractMax();
}
for (int i = 0; i < n; i++) {
if (arr[i-1]<arr[i])
throw new IllegalArgumentException("Error");
}
System.out.println("test MaxHeap completed");
}
}
array
package heap;
public class Array<E>{
private E[] data;
private int size;//记录元素个数
//构造函数,用户创建数组开辟的空间
public Array(int capacity) {
// new 一个E类型的数组
data =(E[]) new Object[capacity];
size = 0;
}
//用户不传参时,默认开辟空间10
public Array() {
this(10);
}
//获取数组中元素个数
public int getSize() {
return size;
}
//获取空间大小
public int getCapacity() {
return data.length;
}
//判断数组是否为空
public boolean isEmpty() {
return size == 0;
}
//在数组最后添加元素2-3
public void addLast(E e) {
// if (size == data.length)
// throw new IllegalArgumentException("Addlast failed.heap.Array is full");
// data[size] = e;
// size++;
add(size,e);
}
//在首位置添加元素
public void addFirst(E e){
add(0,e);
}
//指定位置添加元素
//元素从后往前挪把指定位置空出来
public void add(int index,E e){
if (size == data.length){
resize(data.length * 2);
}
if (index<0||index>size)
throw new IllegalArgumentException("Add failed.Require index>=0 and index<=size");
for (int i=size-1;i>=index;i--){
data[i+1]=data[i];
}
data[index]=e;
size++;
}
private void resize(int capacity) {
E[] newData = (E[]) new Object[capacity];
for (int i = 0; i < size; i++) {
newData[i] = data[i];
}
data=newData;
}
//获取index索引的位置
public E get(int index){
if (index<0||index>=size)
throw new IllegalArgumentException("Add failed.Require index>=0 and index<=size");
return data[index];
}
public E getLast(){
return get(size-1);
}
public E getFirst(){
return get(0);
}
//更新数组元素
public void set(int index,E e){
if (index<0||index>=size)
throw new IllegalArgumentException("Add failed.Require index>=0 and index<=size");
data[index]=e;
}
//是否包含某元素
public boolean contains(E e){
for (int i = 0; i < size; i++) {
if (e.equals(data[i]))
return true;
}
return false;
}
//返回所要查找的元素的索引
public int find(E e){
for (int i = 0; i < size; i++) {
if (e.equals(data[i]))
return i;
}
return -1;
}
//删除索引处的某个元素并返回,将索引之后的元素向前移动
public E remove(int index){
if (index<0||index>size)
throw new IllegalArgumentException("Add failed.Require index>=0 and index<=size");
E result=data[index];
for (int i = index+1; i < size; i++) {
data[i-1]=data[i];
}
size--;
if (size==data.length/4&&data.length/2!=0){
resize(data.length/2);
}
return result;
}
//删除头元素
public E removeFirst(){
return remove(0);
}
//删除最后一个元素
public E removeLast(){
return remove(size-1);
}
//删除某个元素
public void removeElement(E e){
int index = find(e);
if (index!=-1)
remove(index);
}
//交换元素
public void swap(int i,int j){
if (i<0||i>=size||j<0||j>=size){
throw new IllegalArgumentException("Index is illegal");
}
E t =data[i];
data[i] = data[j];
data[j] = t;
}
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(String.format("heap.Array:size=%d,capacity =%d\n",size,data.length));
stringBuilder.append("[");
for (int i=0;i<size;i++){
stringBuilder.append(data[i]);
if (i!=size-1)
stringBuilder.append(",");
}
stringBuilder.append("]");
return stringBuilder.toString();
}
}