堆和堆排序
首先要知道堆,堆首先是一颗完全二叉树(完全二叉树:对满二叉树的节点连续编号,自上而下,自左到右,当且仅当每个节点都与满二叉树一一对应时,该二叉树为完全二叉树),在完全二叉树的所有非终端节点都比左右子节点大或者都比左右子节点小,符合条件的就是堆。
堆有大顶堆和小顶堆之分,大顶堆就是所有非终端节点都比左右子节点大。而小顶堆刚好相反。在这里以大顶堆为例。
堆排序就是每次输出堆顶元素,接着将剩余的n-1个元素的序列重新排成一个堆,最后将所有元素输出自然就能排出一个有序序列。所以堆排序需要解决两个问题:
(1)将一个无序的序列排成一个堆。
(2)在输出堆顶元素后将剩余的元素重新排成一个堆。
具体编码
在这里解决第一个问题很简单,我可以在插入元素的时候就将序列排成堆。具体如下:
public boolean insert(int data){
if(currentIndex<=maxIndex){
Node newnode=new Node(data);
node[currentIndex]=newnode;
tricleUp(currentIndex++);
return true;
}else{
return false;
}
}
在上面代码中每插入一个元素就new一个节点,节点中存有数据,上面关键代码就是调用tricleUp方法,该方法就是将无序的元素序列排成一个堆。下面给出tricleUp(int index)方法。
public void tricleUp(int index){
int parentIndex=(index-1)/2;//获取父节点
Node bottom=node[index];
while(index>0&&node[parentIndex].getData()<bottom.getData()){
node[index]=node[parentIndex];//一直找到父节点没有比该新增节点大的,然后将那个父节点与它交换
index=parentIndex;
parentIndex=(parentIndex-1)/2;//继续查找当前元素的父节点
}
node[index]=bottom;
}
通过上面的代码,可以知道,每添加一个节点,就找到它的父节点并和父节点比较,如此循环到父节点没有比该新增节点大的,然后将那个父节点与它交换,注意这里的(parentIndex-1)/2,是向下取整,无论添加的是哟子节点还是左子节点对应的都是他们的父节点。
接着是输出堆顶元素,然后解决第二个问题:在输出堆顶元素后调整剩余元素成为一个新堆。
public int remove(){
Node root=node[0];
Node bottom=node[--currentIndex];
node[0]=bottom;
tricleDown(0);//取的都是堆顶元素
return root.getData();
}
同样在输出堆顶元素后也要重新排成堆,在这里使用tricleDown方法,该方法具体是先将堆顶输出,然后把最后一个元素放到堆顶,接着和的左右子节点中最大的比,接着按这个方法循环,直到最后一个元素。具体方法如下:
public void tricleDown(int index){
Node current=node[index];
int largeIndex;
while(index<currentIndex/2){//因为每次比较两个元素,左子节点和右子节点所以是currentIndex/2
int leftpart=index*2+1;//获取左子节点
int rightpart=leftpart+1;//获取右子节点
/*找到子节点中最大元素*/ if(rightpart<=currentIndex&&node[leftpart].getData()>node[rightpart].getData()){
largeIndex=leftpart;
}else{
largeIndex=rightpart;
}
/*再将最大元素与父节点比较*/
if(node[largeIndex].getData()>current.getData()){
node[index]=node[largeIndex];
}else{break;}
index=largeIndex;
}
node[index]=current;
}
至此堆排序已经完成。
下面贴出完整代码:
public class trueheapSort {
public class Node{
private int data;
public Node(int data){
this.data=data;
}
public int getData(){
return data;
}
public void setData(int data){
this.data=data;
}
}
private Node[] node;
private int currentIndex=0;
private int maxIndex;
public trueheapSort(int size){
maxIndex=size;
node=new Node[maxIndex];
}
public boolean insert(int data){
if(currentIndex<=maxIndex){
Node newnode=new Node(data);
node[currentIndex]=newnode;
tricleUp(currentIndex++);
return true;
}else{
return false;
}
}
public void tricleUp(int index){
int parentIndex=(index-1)/2;
Node bottom=node[index];
while(index>0&&node[parentIndex].getData()<bottom.getData()){
node[index]=node[parentIndex];//一直找到父节点没有比该新增节点大的,然后将那个父节点与它交换
index=parentIndex;
parentIndex=(parentIndex-1)/2;
}
node[index]=bottom;
}
public int remove(){
Node root=node[0];
Node bottom=node[--currentIndex];
node[0]=bottom;
tricleDown(0);
return root.getData();
}
public void sort(){
int temp=currentIndex;
for (int i = 0; i <temp; i++) {
System.out.println(remove());
}
}
public void tricleDown(int index){
Node current=node[index];
int largeIndex;
while(index<currentIndex/2){
int leftpart=index*2+1;
int rightpart=leftpart+1;
if(rightpart<=currentIndex&&node[leftpart].getData()>node[rightpart].getData()){
largeIndex=leftpart;
}else{
largeIndex=rightpart;
}
if(node[largeIndex].getData()>current.getData()){
node[index]=node[largeIndex];
}else{break;}
index=largeIndex;
}
node[index]=current;
}
public void display(){
for (int i = 0; i <currentIndex; i++) {
System.out.println(node[i].getData());
}
}
public static void main(String[] args){
trueheapSort heap=new trueheapSort(16);
heap.insert(49);
heap.insert(38);
heap.insert(65);
heap.insert(97);
heap.insert(76);
heap.insert(13);
heap.insert(27);
heap.insert(49);
heap.display();
System.out.println();
heap.sort();
}
}