版权声明:本文为博主原创,未经博主允许不得转载。 https://blog.csdn.net/weixin_36904568/article/details/88666727
一:堆
1:定义
堆是一棵完全二叉树,它的根结点是所有结点中最大或最小的,较大或较小的结点靠近根结点。
2:堆的分类
- 每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆。ki>=k2i+1,ki>=k2i
- 每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。ki<=k2i+1,ki<=k2i
3:构造堆
static int[] heap; //存放堆
//构造堆
public static int[] build(int[] arr) { //将数组一个个上浮到堆上
heap = new int[arr.length + 1];
for (int i = 0; i < arr.length; i++) {
swim(i+1,arr[i]);
}
return heap;
}
//上浮
public static void swim(int index,int key) {
heap[index] = key; //先将待检查的记录放入堆中
while (index > 1 && heap[index] > heap[index/2]) { //如果记录比根结点大,则需要上浮
int max = index;
if(index/2 == 1 && heap[index]<heap[index-1]) //找出需要上浮的结点或兄弟结点
max = index - 1;
SortUtil.swap(max,index /= 2,heap); //上浮
}
}
二:优先队列
1:定义:支持删除最大元素和增加元素的队列
2:抽象数据类型
- MaxPQ(int max):创建一个最大容量为max的优先队列
- MaxPQ(Key[] a) :用a[]中的元素创建一个优先队列
- void Insert(Key v) :向优先队列中插人一个元素
- Key max(): 返回最大元素
- Key delMax(): 删除并返回最大兀素
- boolean i sEmpty(): 返回队列是否为空
- int size() 返回优先队列中的元素个数
3:存储结构
(1):使用数组
/**
* 用数组实现优点队列
*/
public class ArrayPQ<T> {
//创建数组保存值
private T[] arr;
//创建顶部指针
private int N = 0;
public ArrayPQ(int len){
arr = (T[]) new Object[len];
}
public ArrayPQ(T[] array){
arr = (T[]) new Object[array.length];
for (int i = 0; i < array.length; i++) {
arr[i] = array[i];
}
}
public void resize(int max){
T[] array = (T[]) new Object[max];
array = Arrays.copyOf(arr,arr.length);
arr = array;
}
//无序入栈,出栈时使用直接选择排序
public void insert_notSorted(T element){
if(N != arr.length)
arr[N++] = element;
else
resize(arr.length*2);
}
//有序入栈,使用插入排序
public void insert_sorted(T element){
if(N != arr.length)
{
int i;
for (i = N; i >0 && compareTo(arr[i-1],element) > 0; i--) {
arr[i] = arr[i-1];
}
arr[i] = element;
N++;
}
else
resize(arr.length*2);
}
//取栈顶元素,直接选择排序
public T max_notSorted(){
if(N>0)
{
if(N > 0 && N == arr.length/4)
resize(arr.length/2);
int max = N-1;
for (int i = 0; i < N - 1; i++) {
if(compareTo(arr[max],arr[i]) < 0)
max = i;
}
if(max != N-1)
swap(max,N-1);
return arr[N-1];
}
else
return null;
}
//取栈顶元素
public T max_sorted(){
if(N>0)
{
if(N > 0 && N == arr.length/4)
resize(arr.length/2);
return arr[N-1];
}
else
return null;
}
//出栈,如果栈过大则压缩栈
public T delMax_sorted() throws EmptyStackException {
T maxKey = null;
if(N>0)
{
maxKey = arr[N-1];
arr[--N] = null;
if(N > 0 && N == arr.length/4)
resize(arr.length/2);
}
else
throw new EmptyStackException();
return maxKey;
}
//出栈,直接选择排序
public T delMax_notSorted() throws EmptyStackException {
T maxKey = null;
if(N>0)
{
int max = N-1;
for (int i = 0; i < N; i++) {
if(compareTo(arr[max],arr[i]) < 0)
max = i;
}
if(max != N-1)
swap(max,N-1);
maxKey = arr[N-1];
arr[--N] = null;
if(N > 0 && N == arr.length/4)
resize(arr.length/2);
}
else
throw new EmptyStackException();
return maxKey;
}
//是否为空栈
public boolean isEmpty(){
return N==0;
}
//栈的大小
public int size(){
return N;
}
//比较
public int compareTo(T a,T b) {
Class tClass = a.getClass();
if(tClass == Integer.class)
{
if((Integer)a > (Integer)b)
return 1;
if((Integer)a == (Integer)b)
return 0;
return -1;
}
return a.toString().compareTo(b.toString());
}
//交换
public void swap(int i, int j){
T temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
(2):使用链表
/**
* 链表实现优先队列
* @param <T>
*/
public class LinkedPQ<T> {
//头结点
private LinkNode<T> head;
//链表长度
private int size;
public LinkedPQ() {
head = new LinkNode<>();
size = 0;
}
public LinkedPQ(T ele) {
head = new LinkNode<>();
LinkNode<T> node = new LinkNode<>(ele);
head.setNext(node);
size = 1;
}
public LinkedPQ(T[] array) {
head = new LinkNode<>();
LinkNode<T> node = new LinkNode<>(array[0]);
head.setNext(node);
LinkNode<T> temp = node;
for (int i = 1; i < array.length; i++) {
node = new LinkNode<>(array[i]);
temp.setNext(node);
temp = node;
}
size = array.length;
}
//获取链表长度
public int getSize() {
return size;
}
//判断链表是否为空
public boolean isEmpty() {
return size == 0;
}
//无序入栈
public void insert_notSorted(T ele) {
LinkNode<T> temp = new LinkNode<>(ele);
LinkNode<T> node = head.getNext();
if (node != null)
temp.setNext(node);
head.setNext(temp);
size++;
}
//有序入栈
public void insert_sorted(T ele) {
LinkNode<T> temp = new LinkNode<>(ele);
LinkNode<T> node = head.getNext();
while (node != null) {
if (compareTo(node.getData(), ele) < 0)
break;
LinkNode<T> next = node.getNext();
if (next == null) {
node.setNext(temp);
size++;
return;
}
if (compareTo(next.getData(), ele) < 0)
{
node.setNext(temp);
temp.setNext(next);
size++;
return;
}
node = node.getNext();
}
if (node != null)
temp.setNext(node);
head.setNext(temp);
size++;
}
//有序出栈
public LinkNode<T> delMax_sorted() {
LinkNode<T> node = head.getNext();
if (node != null) {
LinkNode<T> temp = node.getNext();
head.setNext(temp);
size--;
}
return node;
}
//获取栈顶元素
public LinkNode<T> max_sorted() {
LinkNode<T> node = head.getNext();
return node;
}
//无序出栈
public LinkNode<T> delMax_notSorted() {
LinkNode<T> node = head.getNext();
LinkNode<T> max = node;
LinkNode<T> prev = null;
LinkNode<T> temp = null;
if (node != null && node.getNext() == null) {
head.setNext(node);
size--;
} else
{
while (node != null && node.getNext() != null) {
temp = node.getNext();
if (compareTo(max.getData(), temp.getData()) < 0) {
max = temp;
prev = node;
}
node = temp;
}
if(prev != null)
prev.setNext(max.getNext());
else
head.setNext(max.getNext());
size --;
}
return max;
}
//获取栈顶元素
public LinkNode<T> max_notSorted() {
LinkNode<T> node = head.getNext();
LinkNode<T> max = node;
while (node != null && node.getNext() != null) {
LinkNode<T> next = node.getNext();
if (compareTo(max.getData(), next.getData()) < 0)
max = next;
node = next;
}
return max;
}
//比较
public int compareTo(T a, T b) {
Class tClass = a.getClass();
if (tClass == Integer.class) {
if ((Integer) a > (Integer) b)
return 1;
if ((Integer) a == (Integer) b)
return 0;
return -1;
}
return a.toString().compareTo(b.toString());
}
}
(3):使用堆
/**
* 用堆实现优先队列
*/
public class HeapPQ<T> {
private T[] heap; //用堆存放队列
private int size; //记录堆的大小
public HeapPQ(int len) {
heap = (T[])new Object[len];
}
//构造堆
public HeapPQ(T[] arr) {
heap = (T[])new Object[arr.length + 1];
for (int i = 0; i < arr.length; i++) {
swim(i+1,arr[i]);
}
}
//获取链表长度
public int getSize() {
return size;
}
//判断链表是否为空
public boolean isEmpty() {
return size == 0;
}
//调整堆大小
public void resize(int max){
T[] array = (T[]) new Object[max];
System.arraycopy(heap,1,array,1,size);
// array = Arrays.copyOf(heap,heap.length);
heap = array;
}
//插入
public void insert(T key) {
swim(size+1,key);
}
//获得最大值
public T max(){
return heap[1];
}
//删除最大值
public T delMax(){
T max = heap[1];
swap(1,size,heap);
heap[size--] = null;
sink(1);
return max;
}
//上浮
public void swim(int index,T key) {
if(index > heap.length - 1)
resize(heap.length*2);
heap[index] = key; //先将待检查的记录放入堆中
size++;
while (index > 1 && compareTo(heap[index],heap[index/2]) > 0) { //如果记录比根结点大,则需要上浮
int max = index;
if(index/2 == 1 && compareTo(heap[index],heap[index - 1]) < 0) //找出需要上浮的结点或兄弟结点
max = index - 1;
swap(max,index /= 2,heap); //上浮
}
}
//下沉
public void sink(int key){
if(size > 0 && size == heap.length/4)
resize(heap.length/2);
while (2 * key <= size) { //在树的范围内找
int j = 2 * key;
if(j + 1 <= size && compareTo(heap[j],heap[j+1]) < 0) //找出较大的孩子
j++;
if(compareTo(heap[key],heap[j]) >= 0) //如果根节点比较小就下沉
break;
swap(key,j,heap);
key = j;
}
}
//比较
public int compareTo(T a, T b) {
Class tClass = a.getClass();
if (tClass == Integer.class) {
if ((Integer) a > (Integer) b)
return 1;
if ((Integer) a == (Integer) b)
return 0;
return -1;
}
return a.toString().compareTo(b.toString());
}
public void swap(int i,int j,T[] arr){
T temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
三:索引优先队列:
可以用索引引用优先队列的元素,做出更改
1:抽象数据类型
- IndexMinPQ(int maxN) 创建一个最大容量为maxN的优先队列,索引的取值范围为 0 至 maxN-1
- void insert(int k, Item item) 插人一个元素,将它和索引k相关联
- void change(int k, Item item) 将索引为k的元素素设为item
- boolean contains(int k) 是否存在索引为k的元素
- void delete(int k) 删去索引k及其相关联的元素
- Item min() 返回最小元素
- int minlndex() 返回最小元素的索引
- int delMin() 删除最小元素并返回它的索引
- boolean isEmptyO 优先队列是否为空
- int size() 优先队列中的元素数量
2:实现
- 用一个数组记录索引对应的元素在树中的序号
- 用一个数组记录序号对应的元素索引
- 在调整元素时还要调整序号和索引
- 在删除元素时应该维护数组
public class IndexPQ<T> {
private T[] heap; //用堆存放队列
private int size; //记录堆的大小
private int[] index; //记录元素的索引在树中的位置序号
private int[] indexInTree; //记录树中序号对应的元素索引
public IndexPQ(int len) { //初始化堆和索引
heap = (T[])new Object[len + 1];
index = new int[len + 1];
indexInTree = new int[len + 1];
for (int i = 1; i < index.length; i++) {
index[i] = -1;
}
}
//构造堆
public IndexPQ(T[] arr) {
heap = (T[])new Object[arr.length + 1];
index = new int[arr.length + 1];
indexInTree = new int[arr.length + 1];
for (int i = 0; i < arr.length; i++) {
swim(i+1);
index[i] = i+1;
indexInTree[i] = i+1;
}
}
//获取链表长度
public int getSize() {
return size;
}
//判断链表是否为空
public boolean isEmpty() {
return size == 0;
}
//调整堆大小
public void resize(int max){
T[] array = (T[]) new Object[max];
System.arraycopy(heap,1,array,1,size);
heap = array;
}
//包含
public boolean contains(int k){
//判断索引中是否含有k
if(k < 0 || k > index.length-1)
return false;
return index[k] != -1;
}
//获取索引k对应的元素
public T get(int k){
return heap[index[k]];
}
//获取索引k对应的序号
public int getIndex(int k){
return indexInTree[k];
}
//插入
public void insert(int k,T key) {
//判断索引是否在堆的界限内
if(k < 0)
return;
if(k > index.length - 1)
{
resize(index.length*2);
resize(indexInTree.length*2);
}
if(size+1 > heap.length - 1)
resize(heap.length*2);
//先将待检查的记录放入堆中,记录序号和索引
size++;
heap[size] = key;
index[k] = size;
indexInTree[size] = k;
//调整记录
swim(size);
}
//更改
public void change(int k,T key){
//判断索引是否在堆的界限内
if(!contains(k))
insert(k,key);
//确定索引k的元素在树中的序号,放入待调整的记录
int treeIndex = index[k];
heap[treeIndex] = key;
//调整元素
swim(treeIndex);
sink(treeIndex);
}
//删除指定元素
public void delete(int k){
//判断索引是否在堆的界限内
if(!contains(k))
return;
int treeIndex = index[k]; //确定索引k的元素在树中的序号
//把要删除的元素与最后一个元素交换,同时减小堆的个数
swap(treeIndex,size--,heap);
//记得交换序号和索引
SortUtil.swap(k,indexInTree[size+1],index);
SortUtil.swap(treeIndex,size+1,indexInTree);
//调整元素
swim(treeIndex);
sink(treeIndex);
//释放结点,重新初始化结点的序号和索引
heap[size+1] = null;
index[k] = -1;
indexInTree[size+1] = -1;
}
//获得最大值
public T max(){
return heap[1];
}
//删除最大值
public int delMax(){
int maxIndex = indexInTree[1]; //获取最大值的索引
//交换最大值和最后一个元素,同时减小堆
swap(1,size--,heap);
//记得交换序号和索引
SortUtil.swap(maxIndex,indexInTree[size+1],index);
SortUtil.swap(1,size+1,indexInTree);
//下沉第一个元素
sink(1);
//释放结点并初始化索引和序号
index[maxIndex] = -1;
heap[size+1] = null;
indexInTree[size+1] = -1;
return maxIndex;
}
//返回最大值的索引
public int maxIndex(){
return indexInTree[1];
}
//上浮
public void swim(int index) {
while (index > 1 && compareTo(heap[index],heap[index/2]) > 0) { //如果记录比根结点大,则需要上浮
int max = index;
if(index/2 == 1 && compareTo(heap[index],heap[index - 1]) < 0) //找出需要上浮的结点或兄弟结点
max = index - 1;
swap(max,index/2,heap); //上浮
SortUtil.swap(max,index/2,this.index);
SortUtil.swap(max,index/2,this.indexInTree);
index /= 2;
}
}
//下沉
public void sink(int key){
if(size > 0 && size == heap.length/4)
resize(heap.length/2);
while (2 * key <= size) { //在树的范围内找
int j = 2 * key;
if(j + 1 <= size && compareTo(heap[j],heap[j+1]) < 0) //找出较大的孩子
j++;
if(compareTo(heap[key],heap[j]) >= 0) //如果根节点比较小就下沉
break;
swap(key,j,heap);
SortUtil.swap(key,j,this.index);
SortUtil.swap(key,j,this.indexInTree);
key = j;
}
}
//比较
public int compareTo(T a, T b) {
Class tClass = a.getClass();
if (tClass == Integer.class) {
if ((Integer) a > (Integer) b)
return 1;
if ((Integer) a == (Integer) b)
return 0;
return -1;
}
return a.toString().compareTo(b.toString());
}
public void swap(int i,int j,T[] arr){
T temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}