• 堆排序


    堆的定义如下:

    n个元素的序列{k0,k1,...,ki,…,k(n-1)}当且仅当满足下关系时,称之为堆。

    "ki<=k(2i),ki<=k(2i+1);或ki>=k(2i),ki>=k(2i+1).(i=1,2,…,[n/2])"

    若将和此次序列对应的一维数组(即以一维数组作此序列的存储结构)看成是一个完全二叉树,

    若完全二叉树中每一个节点的值都大于或等于任意一个子节点的值(如果有的话),称之为大顶堆。

    若完全二叉树中每一个节点的值都小于或等于任意一个子节点的值(如果有的话),称之为小顶堆。

    由此,若序列{k0,k1,…,k(n-1)}是堆,则堆顶元素(或完全二叉树的根)必为序列中n个元素的最小值(或最大值)。

    倘若给堆中每一个节点都赋予一个整数值标签,根节点被标记为0,对于每一个标记为i的节点,其左子节点(若存在的话)被标记为2*i+1,其右子节点(若存在的话)被标记为2*i+2,对于一个标记为i的非根节点,其父节点被标记为(i-1)/2。使用这个标记,我们能够将堆存储在数组中,节点存储在数据中的位置就使其标签。

    堆排序示例:

    规则:

    1.初始化i=0,先后查看节点i的左子节点2*i+1、右子节点2*i+2,如果发现违反了堆的定义,则交换2个节点的值(编号只跟位置有关,也就是数组中的下标),置i=0

    2.如果没有发现违反堆的定义,则置i=i+1,返回步骤1

    3.当i==n的时候,将0号位置上的元素放置到n号位置上,置i=0,置n=n-1,返回步骤1,对位置为[0, n]范围内的元素重复上述操作

    示意图如下:数组中的值依次是17,8,45,84,2,94,这次排序的最终结果是把最大的94放到了序列末尾

    下面是剩下的元素的排序过程:

    代码如下:

     1 package sorts;
     2 
     3 import java.util.Arrays;
     4 
     5 public class  Heap<T extends Comparable<T>> // 小顶堆,也就是说小的数据在堆顶部
     6 {
     7     // index starts from 0
     8     private int parent(int index) {
     9         if (index%2==0) {
    10             return ( index / 2 ) - 1;
    11         } else {
    12             return index / 2;
    13         }
    14     }
    15     
    16     private int lchild(int index) {
    17         return index * 2 + 1;
    18     }
    19     
    20     private int rchild(int index) {
    21         return index * 2 + 2;
    22     }
    23     
    24     
    25     public void heap_sort(T[] a,int n){
    26         if(n>0){
    27             init_sort(a,n);//初始化堆,找出最大的放在堆顶
    28             swap(a, 0, n);
    29             heap_sort(a, n-1); // recursively
    30         }
    31     }
    32     
    33     private void swap(T[] a, int index1, int index2) {
    34         T temp = a[index1];
    35         a[index1] = a[index2];
    36         a[index2] = temp;
    37     }
    38 
    39     private void init_sort(T[] a,int n){        
    40         int m=(n+1)/2;    
    41         for(int i=0;i<m;i++){
    42             boolean flag=min_heapify(a,n,i);
    43             //如果孩子之间有交换,就要重新开始
    44             if(flag){
    45                 i=-1;
    46             }
    47         }
    48     }
    49     
    50     //返回一个标记,如果有根与孩子交换就要重新从顶根开始查找不满足最大堆树结构
    51     private boolean min_heapify(T a[],int n,int i){
    52         int l_child=lchild(i);//左孩子
    53         int r_child=rchild(i);//右孩子
    54         if(r_child>n){           //判断是否有右孩子,没有的话直接比较,小于右孩子则交换
    55             if(a[i].compareTo(a[l_child])<0){
    56                 swap(a, i, l_child);
    57                 return true;
    58             }else{
    59                 return false;
    60             }
    61         }
    62         //在根与两个孩子之间找出最大的那个值进行交换
    63         if(a[i].compareTo(a[l_child])<0){
    64             if(a[l_child].compareTo(a[r_child])>0){
    65                 //交换根与左孩子的值
    66                 swap(a, i, l_child);
    67                 return true;
    68             }else{
    69                 //交换根与右孩子的值
    70                 swap(a, i, r_child);
    71                 return true;
    72             }
    73         }else if(a[i].compareTo(a[r_child])<0){
    74             //交换根与右孩子的值
    75             swap(a, i, r_child);
    76             return true;
    77         }
    78         return false;
    79             
    80     }
    81     public static void main(String[] args) 
    82     {
    83         Heap h = new Heap();
    84         Integer [] a={17,8,45,84,2,94};
    85         h.heap_sort(a,a.length-1);
    86         System.out.println(Arrays.toString(a));
    87     }
    88 }
  • 相关阅读:
    wordpress建个人博客
    函数(一)
    字符串格式化
    集合运算
    基本数据类型(二)
    基本数据类型(一)
    分享一个下片神器
    Proxyee
    基本运算符
    条件语句和while循环
  • 原文地址:https://www.cnblogs.com/qrlozte/p/3958598.html
Copyright © 2020-2023  润新知