堆排序

大顶堆的定义:每一个父节点都大于其子结点,根结点是最大的结点

数组转换为堆:层次遍历,第n层填满2^(n-1)次个,最后一层可以填满也可以不填满

第i个结点的左子结点为2*i+1 右子结点为2*i+2

堆结点的基本思想:将数组构造为大顶堆,把根结点放到无序数组的最后

剩余的元素无序,继续构造大顶堆,将根节点放到无序数组后

…………

重复以上步骤 最后可以得到一个有序数组

堆排序的完整代码如下:

 public static void heapSort(int[] arr)
        {
            int temp;
            //最后一个非叶子结点:arr.Length / 2 - 1
            for (int i = arr.Length / 2 - 1; i >= 0; i--)
            {
                adjustHeap(arr, i, arr.Length);
            }//for循环结束后得到了第一个大顶堆
            for (int j = arr.Length-1; j > 0; j--)
            {
                //交换 把根节点沉到最后
                temp = arr[j];
                arr[j] = arr[0];
                arr[0] = temp;
                //排好后仍有j个元素无序 如第一轮排完后只有一个元素有序,剩余arr.Length-1
                //个元素无序,所以无序数组长度为j
                //每次构造大顶堆都是从头开始构造的
                adjustHeap(arr, 0, j);
            }
        }
        //将数组转换为大顶堆
        /// <summary>
        /// 将以i对应的非叶子结点的数调整为大顶堆
        /// </summary>
        /// <param name="arr">待调整的数组</param>
        /// <param name="i">非叶子结点的索引</param>
        /// <param name="length">多少个元素还是无序 length逐渐减少</param>
        public static void adjustHeap(int[] arr, int i, int length)
        {
            int temp = arr[i];//先取出当前元素的值
            //k=i*2+1是i结点的左子节点 k=i*2+2是i结点的右子结点
            for (int k = i * 2 + 1; k < length; k = k * 2 + 1)
            {
                //k+1<length为了防止数组越界
                if (k + 1 < length && arr[k] < arr[k + 1])//i的左子结点小于右子结点
                {
                    k++;//k指向右子节点
                }
                if (arr[k] > temp)//子结点大于父结点
                {
                    arr[i] = arr[k];
                    i = k;//让i指向k继续循环 i可以理解为用来跟踪本轮循环最小值的位置
                }
                else
                {
                    break;//break的原因是从左到右,从下到上调整
                }
            }
            //for循环结束后 已经将i为父结点的树的最大值放在了最顶上(局部大顶堆)
            arr[i] = temp;//将temp值放到调整后的位置
        }

 

posted @ 2020-11-02 11:05  这总没有了吧  阅读(50)  评论(0编辑  收藏  举报