堆排序的思路以及代码的实现

关于堆的一些知识点回顾

  1. 堆是一个完全二叉树
  2. 完全二叉树即是:若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。
  3. 堆满足两个性质: 堆的每一个父节点数值都大于(或小于)其子节点,堆的每个左子树和右子树也是一个堆。
  4. 堆分为最小堆和最大堆。最大堆就是每个父节点的数值要大于孩子节点,最小堆就是每个父节点的数值要小于孩子节点。排序要求从小到大的话,我们需要建立最大堆,反之建立最小堆。
  5. 堆的存储一般用数组来实现。假如父节点的数组下标为i的话,那么其左右节点的下标分别为:(2*i+1)和 (2*i+2)。如果孩子节点的下标为j的话,那么其父节点的下标为(j-1)/2。
  6. 完全二叉树中,假如有n个元素,那么在堆中最后一个父节点位置为(n/2-1)。

算法思想

  1. 建立堆
  2. 调整堆
  3. 交换堆顶元素和堆的最后一个元素

    假如现在有一个数组a[8]={100,33,3,7,11,6,8,5};首先我们要建立完全二叉树。
    如下图所示:

这里写图片描述

然后根据各个父节点,进行一个划分。如图所示:

这里写图片描述

该算法的就是将各个父节点与其自己的孩子结点进行对比,然后交换的过程。根据例子,建立一个最大堆,要求每一个父节点的数值是大于孩子节点的。顺序是从最后一个父节点开始(从左至右,从下至上)。所以第一个父节点是数组下标为3的7,黄色区域中的父节点与孩子节点对比后,发现父节点已经大于孩子节点了,所以不用进行交换了。接下来的顺序就是紫色框中的二叉树,就是数组下标为2的数字3,以数字3为父节点,对比它的孩子节点,从左到右,发现右孩子的数值比父节点大,那么将右节点和父节点进行数值交换。交换后的堆如图所示:
这里写图片描述

交换结束后,再看蓝色框中的二叉树,就是以数组下标为1的数字33,以33为父节点,看它的孩子节点是否大于父节点,结果发现不大于,则不用交换。此时这个完全二叉树已经是一个堆。
接下来可以讲堆顶元素和堆的最后一个元素进行互换,然后再降最后一个元素至于完全二叉树外。
这里写图片描述

此时完全二叉树中,除去100这个元素之后,这个完全二叉树已经不满足堆的性质,所以要进行调整,此时的每次调整要从根节点(和创建堆不一样)开始进行调整,而且父节点和孩子节点交换后,要追踪到交换的孩子节点上(我用浅蓝色标志的部分)。
这里写图片描述

此时33和5交换了位置,那么就要从5为父节点,开始往下再和孩子节点进行比较,此时发现孩子节点和父节点中最大为11,那么将11和父节点(即数字5)互换位置。

这里写图片描述

此时堆已经调整好,再将堆顶元素和堆的最后一个元素互换,即将33和3互换,然后再降33至于完全二叉树外。

这里写图片描述

此时再进行堆的调整,从根开始。
这里写图片描述

这里写图片描述

此时调整完堆后,再将堆顶元素和最后一个元素互换位置,即将11和6互换,再将11至于完全二叉树外。

这里写图片描述

此时再进行完全二叉树的调整,即就是白色填充的元素进行调整。从根开始,按照上面的方法。
这里写图片描述

此时又是一个调整好的堆,将堆顶元素和最后一个元素互换。

这里写图片描述

再进行完全二叉树的调整
这里写图片描述

此时再进行堆顶元素和最后一个元素的互换
这里写图片描述

再进行完全二叉树的调整

这里写图片描述

最后进行堆顶元素的互换:

这里写图片描述

最后一次调整:
这里写图片描述

最后一次堆顶元素交换:

这里写图片描述

此时数组已经是一个有序数组,是一个生序数组,用for循环输出即可。


代码实现(C语言)


#include<stdio.h>

void swap(int *a, int *b)
{
    int p;
    p = *a;
    *a = *b;
    *b = p;
}

void adjustheap(int *arr, int i, int len)
{
    int j = i*2+1;
    while(j < len)
    {
        if(j+1<len && arr[j] < arr[j+1]) //建立大堆,若左孩子小于右孩子,将j取值为右孩子的下标,右孩子再与父结点比较
        {
            j++;
        }
        //将左右孩子中,数值最大的与父结点进行比较,若孩子结点比父结点小,说明父结点的数值比左右孩子都大,不需要交换
        if(arr[i] > arr[j])
        {
            break;//说明该父结点和其孩子结点调整结束,退出循环,从下一个父结点调整
        }
        swap(&arr[i], &arr[j]);
        //交换之后还要考虑该目前j结点与自己的孩子结点的数值比较,还要进行调整,将i当前结点换成j结点所在位置
        i = j;
        j = 2*i+1;
    }
}

void makeheap(int *arr, int n)
{
    int i;
    for(i=n/2-1; i>=0; i--)//要从最后一个父节点开始调整堆
    {
        adjustheap(arr, i, n);
    }
}

void heapsort(int *arr, int len)
{
    int i = 0;
    makeheap(arr, len);
    //每次排出最大的一个元素之后,将该元素排除在堆外,调整堆后交换堆顶元素和堆的最后一个元素
    for(i=len-1; i>=0; i--)//所以要从元素最后一个开始
    {
        swap(&arr[i], &arr[0]);
        /*交换好堆后,重新调整堆*/
        adjustheap(arr, 0, i);      
    }
}

int main()
{
    int a[8]={100,33,3,7,11,6,8,5};
    int n = 8;
    heapsort(a, n);
    for(int i=0; i<8; i++)
    {
        printf("%d ",a[i]);
    }
    printf("\n");
    return 0;
}


  • 25
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
### 回答1: 好的,下面是一个 Java 堆排序的完整代码示例: ``` import java.util.Arrays; public class HeapSort { public static void main(String[] args) { int[] arr = {9, 8, 7, 6, 5, 4, 3, 2, 1}; sort(arr); System.out.println(Arrays.toString(arr)); } public static void sort(int[] arr) { // 将数组堆化 for (int i = arr.length / 2 - 1; i >= 0; i--) { heapify(arr, i, arr.length); } // 将堆顶元素与末尾元素交换,将最大元素沉到数组末端 // 重复这个过程,直到整个数组有序 for (int i = arr.length - 1; i > 0; i--) { swap(arr, 0, i); heapify(arr, 0, i); } } public static void heapify(int[] arr, int i, int length) { int left = 2 * i + 1; int right = 2 * i + 2; int largest = i; // 找出三个节点中最大的节点 if (left < length && arr[left] > arr[largest]) { largest = left; } if (right < length && arr[right] > arr[largest]) { largest = right; } // 如果最大的节点和当前的节点不同,将它们交换 if (largest != i) { swap(arr, i, largest); heapify(arr, largest, length); } } public static void swap(int[] arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } } ``` 堆排序思路是将数组构建成一个堆,然后将堆顶元素与末尾元素交换,将最大元素沉到数组末端。重复这个过程,直到整个数组有序。 上面的代码中,`heapify` 函数用 ### 回答2: 下面是Java实现堆排序的完整代码: ```java import java.util.Arrays; public class HeapSort { public static void heapSort(int[] arr) { int len = arr.length; // 构建最大堆 for (int i = len / 2 - 1; i >= 0; i--) { heapify(arr, len, i); } // 堆排序 for (int i = len - 1; i >= 0; i--) { // 将根节点与最后一个节点交换 int temp = arr[0]; arr[0] = arr[i]; arr[i] = temp; // 重新将剩余未排序的部分构建成最大堆 heapify(arr, i, 0); } } private static void heapify(int[] arr, int n, int i) { int largest = i; // 初始化根节点为最大值 int left = 2 * i + 1; // 左子节点 int right = 2 * i + 2; // 右子节点 // 如果左子节点大于根节点,将最大值的索引设为左子节点的索引 if (left < n && arr[left] > arr[largest]) { largest = left; } // 如果右子节点大于当前最大值,将最大值的索引设为右子节点的索引 if (right < n && arr[right] > arr[largest]) { largest = right; } // 如果最大值不是根节点,将最大值与根节点交换,并且递归调用heapify方法 if (largest != i) { int swap = arr[i]; arr[i] = arr[largest]; arr[largest] = swap; heapify(arr, n, largest); } } public static void main(String[] args) { int[] arr = { 7, 2, 8, 1, 4, 5, 9, 3, 6 }; System.out.println("排序前:" + Arrays.toString(arr)); heapSort(arr); System.out.println("排序后:" + Arrays.toString(arr)); } } ``` 以上代码实现了使用堆排序算法对一个整数数组进行排序。通过构建最大堆和不断调整堆的过程,将数组排序为升序。可以通过输出结果验证排序算法的正确性。 ### 回答3: Java堆排序的完整代码如下: ```java public class HeapSort { public static void main(String[] args) { int[] arr = {4, 6, 8, 2, 1, 9, 5}; heapSort(arr); System.out.println("排序后的数组:"); for (int num : arr) { System.out.print(num + " "); } } public static void heapSort(int[] arr) { int len = arr.length; // 构建最大堆 for (int i = len / 2 - 1; i >= 0; i--) { heapify(arr, len, i); } // 依次取出堆顶元素,与末尾元素交换位置,并重新调整堆 for (int i = len - 1; i >= 0; i--) { int temp = arr[0]; arr[0] = arr[i]; arr[i] = temp; heapify(arr, i, 0); } } public static void heapify(int[] arr, int len, int i) { int largest = i; // 初始化最大值为当前节点 int left = 2 * i + 1; // 左子节点 int right = 2 * i + 2; // 右子节点 // 比较左子节点与当前节点的值,找出最大值的索引 if (left < len && arr[left] > arr[largest]) { largest = left; } // 比较右子节点与当前节点的值,找出最大值的索引 if (right < len && arr[right] > arr[largest]) { largest = right; } // 如果最大值不是当前节点,则交换它们,并递归调整子节点 if (largest != i) { int swap = arr[i]; arr[i] = arr[largest]; arr[largest] = swap; heapify(arr, len, largest); } } } ``` 以上代码实现堆排序的主要逻辑。首先,通过`heapSort`方法建立一个最大堆,然后依次取出堆顶元素,与末尾元素交换,并重新调整堆,直到整个数组有序。`heapify`方法用于调整堆,它会比较当前节点与其左右子节点的值,找到最大值,并将最大值与当前节点互换位置,然后递归地调整子节点。最后,将排序后的数组打印输出即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值