算法练习——堆排序

堆是一个数据结构,可以看作是一个数组,并且具有完全二叉树的性质,每个结点都对应一个数组的元素。

堆和数组对应的关系类似于一种层序排列。

比如:对于数组   A= {27,17,16,13,10,1,5,7,12,14,8,9}

A数组在堆中表现的情况如下

 

 

1:各结点之间的性质

对于根节点从  0  开始的一个堆,各个结点存在以下关系  

体现在图(2)中

  //计算二叉树的右孩子下标值
    public int findrightChild(int i) {
          return 2*(i+1);
      }
      
      //计算二叉树的左孩子下标值
      public int findLeftChild(int i) {
          return 2*(i+1)-1;
      }
     
     //计算父亲结点的下标值
     public int findParent(int i){
         return (i-1)/2;
     }

 2:什么是最大堆?

 最大堆指的是除了根节点外所有的结点都满足于:根节点的属性值大于孩子结点的属性值。  A[Parent(i)] >= A[i]

 3:如何进行堆排序?

堆排序之前都必须做下面三种操作:

3.1   MaxHeapify()  

  用于维持最大堆的性质   时间复杂度为   O(nlogn)     每次都是在破坏的那个元素开始维持性质  并且是自顶向底开始进行的

伪代码描述:

 1 Max_Heap(A,i)
 2     l = findleftChild(i)
 3     r = findrightChild(i)
 4     if l <= A.headSize && A[l] > A[i]
 5         largest = l
 6     else largest = i
 7     if r <= A.headSize && A[r] > A[largest]
 8         largest = r
 9     if largest != i
10         exchange A[i] with  A[largest]
11         Max_Heap(A, largest)

 

 

在程序的每一步中,从A[i]、A[LEFT(i)]和A[RIGHT(i)]中选出最大的,并将其下标存储在largest中。如果A[i]是最大的,那么以 i 为根结点的子树已经是最大堆,程序结束。

否则,最大元素是i的某个孩子结点,则交换A[i]和A[largest]的值。从而使i及其孩子都满足最大堆的性质。在交换后,下标为largtst的结点的值是原来的A[i],于是以该结点为根的子树又有可能会违反最大堆的性质.因此,需要对该子树递归调用MAX-HEAPIFY。

 

 (1) 首先A[1]违反了最大堆的性质    所以将A[1]与其孩子中更大的一个值作交换,此时    A [1] exchange  A[4]   

(2)A[4]因此不满足最大堆的性质,在继续与其孩子中的更大一个值做交换   

(3)已经到了叶子结点,没有任何的孩子结点,则调出递归的过程

 

该过程的时间复杂度为  O(n)

 

3.2  BuildMaxHeap()    

  创建最大堆    具有线性时间复杂度

思路主要是从低向上的方式将A数组转化为  最大堆的形式

建立堆的伪代码描述:

 

1 Create_heap(A)
2 A.heapSize = A.length;
3 for i = [A.length/2] downto 1
4     Max_Heap(A,i)

 思考:  建立堆的时候为什么  i = [A.length/2]    开始呢?

  当用数组表示存储n个元素的堆时,叶结点下标分别是[n/2]+1,[n/2]+2,[n/2]+3 ...,n

 

 

     由上面的图解值,首先从i = length / 2  开始  使每个结点的子树都满足  最大堆的性质。不断的递归调用MaxHeapify() 方法由低向顶部一步一步实现。

 

3.3  HeapSort()        

   对于一个数组做原址排序(原址排序:任何时候只需要常数个的额外空间来保存临时变量)

最后一步:对于已经排列好的堆 ,我们只需要每次将最后一个结点与根节点作交换,并且取出根节点  ,作为输出元素,然后将剩余的结点再调用  MaxHeapify()  方法,让其他结点仍然具有最大堆 的性质。

1 // (自底向上进行)
2 HeapSort(A)
3     Create_heap(A)
4     for i = A.length downto 2
5         Exchange A[i] with A[1]
6         A.heapSize--
7         Max_Heap(A,i)

 

HEAPSORT过程的时间复杂度是O(nlgn),因为每次调用CreateMaxHeap()的时间复杂度是O(n),而n-1次调用MAXHEAPIFY,每次的时间为O(lgn)。

 

 

 

 

 当所有的元素都递归排序完成,则依次挑出来的元素都为已经排列好的序列。

下面给出具体的实现代码:

 1 package com.hone.heapsort;
 2 
 3 public class HeapSort {
 4     static int[] a = {4,1,3,2,16,9,10,14,8,7};
 5     public static int [] heap =a ;
 6     public static int heapsize = heap.length;
 7     
 8     //1:保证堆满足最大堆的性质
 9     /*
10      * 这里面的性质有一个问题,对于第一个根节点的元素不是最大值的时候,会出现局部
11      * 最大堆  (并不是一个问题,以为每次调用的点,都是从该点开始堆才遭到破坏)
12      */
13     
14     public static  void maxHeap(int[] A , int i){
15         
16         int largest = i; 
17         int l = findLeftChild(i);
18         int r = findrightChild(i);
19         if (l < heapsize && A[l] > A[i]) 
20             largest = l;
21         if (r < heapsize && A[r] > A[largest]) 
22             largest = r;
23         if (largest != i) {
24             swap(A,largest,i);
25             maxHeap(A, largest);
26         }
27         
28     }
29     
30     //2:用于创建最大堆
31     public  void  createHeap(int[] A){
32         for (int i = heapsize/2-1; i >= 0; i--) {
33             maxHeap(A, i);
34         }
35     }
36 
37     //3: 用于堆排序算法
38     public  void heapSort(int[] A){
39         createHeap(A);
40         System.out.print("排序后: ");
41         for (int i = heapsize-1; i >= 0; i--) {
42             swap(A,i,0);
43             System.out.print(A[i]+" ");
44             heapsize --;
45             maxHeap(A, 0);
46         }
47     }
48     
49     // 定义一个方法交换两个数据
50     private static void swap(int[] a,int i,int j) {
51         int temp;
52         temp = a[j];
53         a[j] = a[i];
54         a[i] = temp;
55     }
56     //定义一个方法计算二叉树的右孩子
57     public static int findrightChild(int i) {
58         return 2*(i+1);
59     }
60     
61     //定义一个方法计算二叉树的左孩子
62     public static int findLeftChild(int i) {
63         return 2*(i+1)-1;
64     }
65     
66     
67     public static int findParent(int i){
68         return (i-1)/2;
69     }
70     
71     public static void main(String[] args){
72         HeapSort hs = new HeapSort();
73         System.out.print("原数组: ");
74         for (int i = 0; i < a.length; i++) {
75             System.out.print(a[i]+" ");
76         }
77         System.out.println();
78         hs.heapSort(a);
79     }
80 }

 

 但是,方法并没有得到完整的封装,而且没有很好的用到java中面向对象的思想。

因此代码做如下改变:

 

下面代码转载于:http://www.cnblogs.com/developerY/p/3319618.html     只作为学习使用。

 1 package com.hone.heapsort;
 2 
 3 //定义一个类将MaxHeap单独的类
 4 public class MaxHeap {
 5     int[] heap;
 6     int heapsize;
 7     
 8     public MaxHeap(int[] array)
 9     {
10         this.heap=array;    
11         this.heapsize=heap.length;
12     }
13     
14     public void BuildMaxHeap()
15     {
16         for(int i=heapsize/2-1;i>=0;i--)
17         {
18             Maxify(i);//依次向上将当前子树最大堆化
19         }
20     }
21     
22     public void HeapSort()
23     {
24         for(int i=0;i<heap.length;i++)
25         {
26             //执行n次,将每个当前最大的值放到堆末尾
27             int tmp=heap[0];
28             heap[0]=heap[heapsize-1];
29             heap[heapsize-1]=tmp;
30             heapsize--;
31             Maxify(0);
32         }
33     }
34     
35     public void Maxify(int i)
36     {
37         int l=Left(i);
38         int r=Right(i);
39         int largest;
40         
41         if(l<heapsize&&heap[l]>heap[i])
42             largest=l;
43         else
44             largest=i;
45         if(r<heapsize&&heap[r]>heap[largest])
46             largest=r;
47         if(largest==i||largest>=heapsize)//如果largest等于i说明i是最大元素 largest超出heap范围说明不存在比i节点大的子女
48             return ;
49         int tmp=heap[i];//交换i与largest对应的元素位置,在largest位置递归调用maxify
50         heap[i]=heap[largest];
51         heap[largest]=tmp;
52         Maxify(largest);
53     }
54     
55     public void IncreaseValue(int i,int val)
56     {
57         heap[i]=val;
58         if(i>=heapsize||i<=0||heap[i]>=val)
59             return;
60         int p=Parent(i);
61         if(heap[p]>=val)
62             return;
63         heap[i]=heap[p];
64         IncreaseValue(p, val);
65     }
66     
67     private int Parent(int i)
68     {
69         return (i-1)/2;
70     }
71     private int Left(int i)
72     {
73         return 2*(i+1)-1;
74     }
75     private int Right(int i)
76     {
77         return 2*(i+1);
78     }
79 }

 

 

 1 package com.hone.heapsort;
 2 
 3 public class Demo {
 4     
 5     public static void main(String[] args)
 6     {
 7         int[] array=new int[]{1,2,19,4,7,8,9,10,14,16};
 8         MaxHeap heap=new MaxHeap(array);
 9         System.out.println("执行最大堆化前堆的结构:");
10         printHeapTree(heap.heap);
11         heap.BuildMaxHeap();
12         System.out.println("执行最大堆化后堆的结构:");
13         printHeapTree(heap.heap);
14         heap.HeapSort();
15         System.out.println("执行堆排序后数组的内容");
16         printHeap(heap.heap);
17         
18     }
19     private static void printHeapTree(int[] array)
20     {
21         for(int i=1;i<array.length;i=i*2)
22         {
23             for(int k=i-1;k<2*(i)-1 &&k<array.length;k++)
24             {
25                 System.out.print(array[k]+" ");
26             }
27             System.out.println();
28         }    
29     }
30     private static void printHeap(int[] array)
31     {
32         for(int i=0;i<array.length;i++)
33         {
34             System.out.print(array[i]+" ");
35         }
36     }
39 }

 

posted @ 2017-08-21 20:43  SnailsCoffee  阅读(458)  评论(0编辑  收藏  举报