Java实现堆排序
2015-03-26 13:08
176 查看
上篇博文用Java实现了堆的基本操作,包括建立堆,移除堆顶的元素等。
我们知道,堆是一种弱序的数据结构,也就是说堆中的元素并非完全有序,但是我们可以利用堆的一些操作特性实现排序,使关键字完全有序。基本步骤包括以下几点:
1、初始化堆,直接将关键字依次插入到堆中,而不必每次进行调整。(此时确切的讲,堆数组不满足堆的特性,也暂时称不上是堆)
2、以数组中最后一个元素的父结点为基准,对其进行向下调整,调整完成后,继续对该结点的上一个结点进行向下调整。等对所有元素调整完成后,此时的数组才是真正意义上的堆。(在这里我们并没有在第一步进行数据插入的时候就对每个关键字进行堆的向上调整,因为这样做会调用N次向上调整,而用这里的方法向下调整,只需要调用N/2次向下调整)
3、将堆顶元素取出,将堆最后一个元素放到堆顶,并将取出的堆顶元素放到堆尾,堆的大小减一。对堆顶元素进行向下调整。依次进行这步操作,我们会发现数组尾部的元素关键字是依次有序的,原因就是我们每次从堆顶取出的元素都是最大(大顶堆)或最小值(小顶堆)。
上述三步的代码:
运行结果:
我们知道,堆是一种弱序的数据结构,也就是说堆中的元素并非完全有序,但是我们可以利用堆的一些操作特性实现排序,使关键字完全有序。基本步骤包括以下几点:
1、初始化堆,直接将关键字依次插入到堆中,而不必每次进行调整。(此时确切的讲,堆数组不满足堆的特性,也暂时称不上是堆)
2、以数组中最后一个元素的父结点为基准,对其进行向下调整,调整完成后,继续对该结点的上一个结点进行向下调整。等对所有元素调整完成后,此时的数组才是真正意义上的堆。(在这里我们并没有在第一步进行数据插入的时候就对每个关键字进行堆的向上调整,因为这样做会调用N次向上调整,而用这里的方法向下调整,只需要调用N/2次向下调整)
3、将堆顶元素取出,将堆最后一个元素放到堆顶,并将取出的堆顶元素放到堆尾,堆的大小减一。对堆顶元素进行向下调整。依次进行这步操作,我们会发现数组尾部的元素关键字是依次有序的,原因就是我们每次从堆顶取出的元素都是最大(大顶堆)或最小值(小顶堆)。
上述三步的代码:
Heap heap = new Heap(9); for(int i = 0; i < heap.getMaxSize(); i++){ heap.insertNodeUnsort(i,new HeapNode( (int)(java.lang.Math.random()*100) ) );//这里插入结点,当前结点数并不自增,所以要手动增加 heap.setCurrentSize(i+1); } for(int j = (heap.getCurrentSize()-1-1)/2; j >=0 ;j--){//调整成堆 heap.trickleDown(j); } for(int k = heap.getCurrentSize()-1; k > 0; k--){ HeapNode temp = heap.deleteRootNode();//删除结点后,结点数自减 heap.insertNodeUnsort(heap.getCurrentSize(), temp);//当前结点数的下标的位置是之前最后一个结点的位置 } heap.displayHeap();若仅仅对一个给定的堆进行关键字的有序排序,则只需要进行第三个for循环就可以了。
public HeapNode deleteRootNode(){ if(currentSize == 0){ return null; } HeapNode root = heapArray[0];//需要时可将其返回 heapArray[0] = heapArray[--currentSize]; trickleDown(0);//删除根结点后,将最后一个结点放到堆顶,对其向下进行调整; return root; }
public void trickleDown(int index){ int leftChild ; int rightChild ; while(index < currentSize && index >= 0){ leftChild = 2*index + 1; rightChild = 2*index + 2; if(leftChild >= currentSize){//如果左孩子不存在 return; }else if(rightChild >= currentSize){//如果左孩子存在,右孩子不存在 if(heapArray[leftChild].getKey() > heapArray[index].getKey()){ swapNode(heapArray,index,leftChild); index = leftChild; }else return; } else{//如果左右孩子都存在 if(heapArray[leftChild].getKey() > heapArray[rightChild].getKey()){//若左孩子大 if(heapArray[leftChild].getKey() > heapArray[index].getKey()){//若左孩子比当前值大 swapNode(heapArray,index,leftChild); index = leftChild; } else return; }else{ if(heapArray[rightChild].getKey() > heapArray[index].getKey()){ swapNode(heapArray,index,rightChild); index = rightChild; } else return; } }//end of if-else }//while }//end of method public void swapNode(HeapNode[] array, int index1, int index2){ HeapNode temp = array[index1]; array[index1] = array[index2]; array[index2] = temp; }
public boolean insertNodeUnsort(int index, HeapNode node){ if(maxSize == currentSize){ return false; } heapArray[index] = node; return true; }堆排序的完整代码:
package test2;
class HeapNode{
private int key;
public HeapNode(int key){
this.key = key;
}
public void setKey(int key){
this.key = key;
}
public int getKey(){
return key;
}
}
public class Heap {
private HeapNode[] heapArray;
private int maxSize;
private int currentSize;
public Heap(int maxSize){
this.maxSize = maxSize;
heapArray = new HeapNode[maxSize];
currentSize = 0;
}
public boolean insertNodeUnsort(int index, HeapNode node){ if(maxSize == currentSize){ return false; } heapArray[index] = node; return true; }
public void trickleDown(int index){
int leftChild ;
int rightChild ;
while(index < currentSize && index >= 0){
leftChild = 2*index + 1;
rightChild = 2*index + 2;
if(leftChild >= currentSize){//如果左孩子不存在
return;
}else if(rightChild >= currentSize){//如果左孩子存在,右孩子不存在
if(heapArray[leftChild].getKey() > heapArray[index].getKey()){
swapNode(heapArray,index,leftChild);
index = leftChild;
}else
return;
}
else{//如果左右孩子都存在
if(heapArray[leftChild].getKey() > heapArray[rightChild].getKey()){//若左孩子大
if(heapArray[leftChild].getKey() > heapArray[index].getKey()){//若左孩子比当前值大
swapNode(heapArray,index,leftChild);
index = leftChild;
}
else
return;
}else{
if(heapArray[rightChild].getKey() > heapArray[index].getKey()){
swapNode(heapArray,index,rightChild);
index = rightChild;
}
else
return;
}
}//end of if-else
}//while
}//end of method
public void swapNode(HeapNode[] array, int index1, int index2){
HeapNode temp = array[index1];
array[index1] = array[index2];
array[index2] = temp;
}
public HeapNode deleteRootNode(){
if(currentSize == 0){
return null;
}
HeapNode root = heapArray[0];//需要时可将其返回
heapArray[0] = heapArray[--currentSize];
trickleDown(0);//删除根结点后,将最后一个结点放到堆顶,对其向下进行调整;
return root;
}
class HeapApp{
public static void main(String args[]){
Heap heap = new Heap(5);
for(int i = 0; i < heap.getMaxSize(); i++){
heap.insertNodeUnsort(i,new HeapNode( (int)(java.lang.Math.random()*100) ) );//这里插入结点,当前结点数并不自增,所以要手动增加
heap.setCurrentSize(i+1);
}
heap.displayHeap();
for(int j = (heap.getCurrentSize()-1-1)/2; j >=0 ;j--){//调整成堆
heap.trickleDown(j);
}
heap.displayHeap();
for(int k = heap.getCurrentSize()-1; k > 0; k--){
HeapNode temp = heap.deleteRootNode();//删除结点后,结点数自减
heap.insertNodeUnsort(k, temp);//当前结点数的下标的位置是之前最后一个结点的位置
}
heap.displayHeap();
// heap.insertNode(1);
// heap.insertNode(2);
// heap.insertNode(3);
// heap.insertNode(9);
//
// heap.deleteRootNode();
// heap.displayHeap();
//
// heap.changeNodeKey(2, 8);
// heap.displayHeap();
}
}
运行结果:
31 44 52 52 75 81 82 85 93
相关文章推荐
- 排序算法复习(Java实现)(二): 归并排序,堆排序,桶式排序,基数排序
- 排序算法复习(Java实现)(二): 归并排序,堆排序,桶式排序,基数排序
- 几种常用的排序算法的分析及java实现(希尔排序,堆排序,归并排序,快速排序,选择排序,插入排序,冒泡排序)
- 自主实现的Java实现的构造大小堆、堆排序的算法
- 堆排序详解以及java实现
- 排序算法复习(Java实现)(二): 归并排序,堆排序,桶式排序,基数排序
- 最大堆及堆排序的Java实现_world
- 几种常用的排序算法的分析及java实现(希尔排序,堆排序,归并排序,快速排序,选择排序,插入排序,冒泡排序)
- [原]堆排序的java实现
- [转载]堆排序(HeapSort) Java实现
- 【转】排序算法复习(Java实现)(二): 归并排序,堆排序,桶式排序,基数排序
- java 实现堆排序
- 算法导论Java实现-堆排序(6.4章节)
- 元素排序几种常用的排序算法的分析及java实现(希尔排序,堆排序,归并排序,快速排序,选择排序,插入排序,冒泡排序)
- 堆排序(java实现)
- 【转】排序算法复习(Java实现) (二): 归并排序,堆排序,桶式排序,基数排序
- Java实现快速排序、归并排序、堆排序
- 程序员必知的8大排序(二)-------简单选择排序,堆排序(java实现)
- heapsort堆排序(3种语言实现 c/java/python)
- 堆排序及其JAVA实现