11堆排序

https://blog.csdn.net/weixin_45796387/article/details/114994648?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162509768116780274190983%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=162509768116780274190983&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2alltop_positive~default-1-114994648.first_rank_v2_pc_rank_v29&utm_term=%E4%BA%8C%E5%8F%89%E6%A0%91&spm=1018.2226.3001.4187

————————二叉树详解

堆排序

1.简介

堆的结构可以分为大根堆和小根堆,是一个完全二叉树,而堆排序是根据堆的这种数据结构设计的一种排序,下面先来看看什么是大根堆和小根堆

条件:

1.首先是一个完全二叉树

2.父节点的值大于子节点

2.大根堆和小根堆

性质:每个结点的值都大于其左孩子和右孩子结点的值,称之为大根堆;每个结点的值都小于其左孩子和右孩子结点的值,称之为小根堆。

img

​ 我们对上面的图中每个数都进行了标记,上面的结构映射成数组就变成了下面这个样子。

img

还有一个基本概念:查找数组中某个数的父结点和左右孩子结点,比如已知索引为****i****的数,那么。

1.parent: (i - 1) / 2;

2.child1: 2**i*+1

3.child2: 2**i*+2

3.大堆排序

基本思想:

​ 1.首先将待排序的数组构造成一个大根堆,此时,整个数组的最大值就是堆结构的顶端

​ 2.将顶端的数与末尾的数交换,此时,末尾的数为最大值,剩余待排序数组个数为n-1

​ 3.将剩余的n-1个数再构造成大根堆,再将顶端数与n-1位置的数交换,如此反复执行,便能得到有序数组

4.实现步骤

1.大根堆

思路:从0 到n个节点都需要做一次小堆,三个数进行比较,取最大值,放到三个数顶端,三个数的顶端需要和parent节点比较,直到小于等于0时释放.

void swap(int arr[], int i, int j)
{
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

void buildHeap(int tree[], int max)
{
    int parent = (max - 1) / 2;
    if (parent < 0)//注意是小于0时,不进行了,此时parent没有数据
    {
        return;
    }
    //如果parent节点有,则比较
    if (tree[max] <= tree[parent])
    {
        return; //代表parent节点大,无需交换
    }
    else
    {
        //代表parent节点小,交换
        swap(tree, max, parent);//交换
        buildHeap(tree, parent);//再次与上一个parent节点比较
    }
}

//最小堆排序
void heapify(int tree[], int n, int i)
{
    if (i >= n)
    {
        return;
    }
    int c1 = 2 * i + 1;
    int c2 = 2 * i + 2;
    int max = i;
    if (c1 < n && tree[c1] > tree[max])
    {
        max = c1;
    }
    if (c2 < n && tree[c2] > tree[max])
    {
        max = c2;
    }
    if (max != i)
    {
        //进行交换
        swap(tree, max, i);
        //需要跟parent进行比较,根据公式parent = (i - 1) / 2;
        buildHeap(tree, i);//与上一节点比较
    }
    heapify(tree, n, i + 1);
}

2.每次末尾的数与第一个数交换

img

img

void heap_sort(int tree[], int n)
{
    heapify(tree, n, 0); //进行大顶堆
    //最后一个数与第一个元素交换
    for (int i = n - 1; i > 0; --i)
    {
        swap(tree, i, 0); //末尾的和第一个元素交换
        heapify(tree, i, 0);
    }
}

int main(int argc, char const *argv[])
{
    int tree[] = {3, 10, 5, 8, 1, 7, 6, 9, 2, 100, 200, 120, 11, 30};
    int length = sizeof(tree) / sizeof(tree[0]);
    heap_sort(tree, length);
    for (int i = 0; i < length; i++)
    {
        printf("%d\n", *(tree + i));
    }
    system("pause");
    return 0;
}
3.堆排序的事件复杂度

nlgn:

4.堆应用场景

从10万个数里面选出最小的10个”为例,利用堆排序从无序数组里面选择最大(小)的部分元素。

实现原理:用个无序数组模拟10万个数,取无序数组里面前面的10个数字构建一个大顶堆,从第11个数开始逐个与堆顶元素进行比较,小于堆顶元素则入堆,并重新构建大顶堆,这样能保证堆顶元素始终是最大的。循环完毕之后,堆里面的10个元素就是最小的了。

如果采用堆来实现,则非常容易取到值,取最大元素。

第一次堆:大顶堆堆顶就是最大值,n次

第二次堆:先把顶端元素与最后的元素交换。再次进行大顶堆

第三次堆:…

也就是,需要的次数非常快。

5.总结使用场景

  • 1.适合从无序的数据中,取出部分数据,比如最大的十个数,或者最小的十个数

  • 2.适合大量的数据

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
堆排序是一种基于二叉堆数据结构的排序算法。下面是一个用Python实现的堆排序示例代码: ```python def heapify(arr, n, i): largest = i left = 2 * i + 1 right = 2 * i + 2 if left < n and arr[i] < arr[left]: largest = left if right < n and arr[largest] < arr[right]: largest = right if largest != i: arr[i], arr[largest] = arr[largest], arr[i] heapify(arr, n, largest) def heapSort(arr): n = len(arr) # 构建最大堆 for i in range(n // 2 - 1, -1, -1): heapify(arr, n, i) # 逐个从堆取出元素并进行排序 for i in range(n - 1, 0, -1): arr[i], arr[0] = arr[0], arr[i] # 将当前最大元素移动到数组末尾 heapify(arr, i, 0) return arr # 测试代码 arr = [12, 11, 13, 5, 6, 7] sorted_arr = heapSort(arr) print("排序后的数组:") print(sorted_arr) ``` 这段代码首先定义了两个函数,`heapify`函数用于维护最大堆的性质,`heapSort`函数则是通过调用`heapify`函数实现堆排序。 在`heapify`函数,首先找到当前节点及其左右子节点的最大值,并将最大值与当前节点交换位置,然后递归调用`heapify`函数来修复子树。 在`heapSort`函数,首先构建初始最大堆,然后将堆顶元素(最大值)与末尾元素交换位置,并修复堆的性质。重复这个步骤直到堆为空,此时排序完成。 运行以上代码,将得到输出结果: ``` 排序后的数组: [5, 6, 7, 11, 12, 13] ``` 这就是使用堆排序算法对给定数组进行排序的过程。希望对你有所帮助!如果还有其他问题,请随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值