算法笔记之堆排序

一、对堆排序的相关了解

1、堆排序的运行时间是 O(nlogn) 

2、定义:

heap是一棵具有以下属性的二叉树——

1)它是一棵完全二叉树;

2)每个结点大于或等于它的任意一个孩子。

 

备注:完全二叉树的定义——除了最后一层没填满以及最后一层的叶子都是偏左放置的,其他层都是满的二叉树!

             

3、二叉堆有两种:最大堆和最小堆。在堆排序中我们使用的是最大堆,最小堆常常在构造优先队列时使用。                            

  4、一条路径的深度指的是这条路径的边数,一个结点的深度是指从根结点到该结点的路径的长度。                

                                  

二、对堆进行排序

1)添加新元素

我们可以把堆存储在一个Arraylist里,树根在位置0处,它的两个孩子在位置12。存储规律如下,对于位置在i的结点,它的左孩子在2i+1处,右孩子在2i+2处,而它的父亲在位置(i-1)/2


[java]  view plain copy
  1. //增加一个元素  
  2.     public void add(E object){  
  3.         list.add(object);//先把它放在最后面  
  4.         int currentIndex = list.size()-1;  
  5.         while(currentIndex > 0){  
  6.             //如果比父亲大,则交换  
  7.             int parentIndex = (currentIndex - 1)/2;  
  8.             if (list.get(currentIndex).compareTo(list.get(parentIndex)) > 0) {  
  9.                 E temp = list.get(parentIndex);  
  10.                 list.set(parentIndex, list.get(currentIndex));  
  11.                 list.set(currentIndex, temp);  
  12.             }else {  
  13.                 break;  
  14.             }  
  15.             currentIndex = parentIndex;//一路交换上去,直到根结点为止  
  16.         }  
  17.     }  
  18.       


2)删除并返回当前堆的最大值

返回根元素,并重建堆,重建堆的思路是将最后面的那个元素放到根元素的位置,然后与它的最大子树想比(之前判断是否有左右子树,然后再比较出左右子树哪个更大),如果比最大子树小,那么交换,依次下去,直到当前元素的索引>=list的长度

[java]  view plain copy
  1. public E remove(){  
  2.         if (list.size()== 0) {  
  3.             return null;  
  4.         }else{  
  5.               
  6.             E root = list.get(0);  
  7.             int last = list.size()-1;  
  8.             list.set(0,list.get(last));  
  9.             list.remove(last);  
  10.               
  11.             int currentIndex = 0;  
  12.             while(currentIndex < list.size()){  
  13.                 //它的左右子树索引  
  14.                 int leftChildIndex = 2*currentIndex + 1;  
  15.                 int rightChildIndex = 2*currentIndex + 2;  
  16.                   
  17.                 //找出最大的子树  
  18.                 int maxChildIndex = leftChildIndex;  
  19.                 if (leftChildIndex >= list.size()) {  
  20.                     break;  
  21.                 }else if(rightChildIndex < list.size()){  
  22.                     if (list.get(maxChildIndex).compareTo(list.get(rightChildIndex)) < 0) {  
  23.                         maxChildIndex = rightChildIndex;  
  24.                     }  
  25.                 }  
  26.                   
  27.                 //与根元素比较,根元素小则交换,否则退出循环,此时已经是堆了  
  28.                 if (list.get(currentIndex).compareTo(list.get(maxChildIndex)) < 0) {  
  29.                     E temp = list.get(currentIndex);  
  30.                     list.set(currentIndex, list.get(maxChildIndex));  
  31.                     list.set(maxChildIndex, temp);  
  32.                     //更新当前索引  
  33.                     currentIndex = maxChildIndex;  
  34.                 }else {  
  35.                     break;  
  36.                 }  
  37.             }  
  38.               
  39.             //返回根元素,堆的最大值  
  40.             return root;  
  41.         }  
  42.     }  

3、排序


[java]  view plain copy
  1. /** 
  2.      * 堆排序方法 
  3.      * decription: 
  4.      * @author : linjq 
  5.      */  
  6.       public  <E extends Comparable> void sort(E[] list) {  
  7.         Heap<E> heap = new Heap<E>();  
  8.   
  9.         //构造堆  
  10.         for (int i = 0; i < list.length; i++)  
  11.           heap.add(list[i]);  
  12.   
  13.         //排序  
  14.         for (int i = list.length - 1; i >= 0; i--)  
  15.           list[i] = heap.remove();  
  16.       }  

4、测试该堆排序

[java]  view plain copy
  1. public static void main(String[] args) {  
  2.    Integer[] list = {22, -43225655, -229314,102};  
  3.    HeapSort heapSort = new HeapSort();  
  4.    heapSort.sort(list);  
  5.      
  6.    for (int i = 0; i < list.length; i++)  
  7.      System.out.print(list[i] + " ");  
  8.  }  
测试结果——

三、时间复杂度分析

假设我们现在有n个元素,用h来表示n个元素的高度,由于堆是完全二叉树,于是第一层有1个结点,第二层有两个...h层至少有1个,最多有2^(h - 1)个结点。

 1+2+…+2^(h -2) < n <= 1+2+…+ 2^(h-2 )+ 2^(h -1)

化简即得: 2^(h-1) - 1 < n <= 2^h - 1

 h - 1 < log(n+1) <= h所以 log(n+1) < h<= log(n+1) +1

所以堆的高度是 O (logn)

因为removeadd方法最多情况下需要从根结点追踪到叶子结点,最多耗费的时间不过是h步,n个元素就调用n次这两个方法,因此堆排序的时间复杂度是 O(NlogN)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值