数据结构——堆(堆排序)

简介: 数据结构——堆(堆排序)

1.堆

堆的逻辑结构是一颗完全二叉树

堆的物理结构是一个顺序表

通过下标去实现父子节点关系

leftchild=parent*2+1
rightchild=parent*2+2
parent=(child-1)/2;

就类似于下图

image.png

image.png

2.堆的两个特性

大堆:所有父亲大于等于孩子

小堆:所有父亲小于等于孩子

结构性:用数组表示的完全二叉树

有序性:任意结点的关键字是其子树所有结点的最大值(或最小值)

最大堆”也称“大堆顶”:最大值

最小堆”也称“小堆顶”:最小值

image.png

3 .向下调整算法(以大堆为例)

//向下调整算法(左右子树必须是大堆)
void AdjustDown(int*a,int n,int root)
{
    int parent=root;
    int child=parent*2+1;
    while(child<n)
    {
        if( child+1<n && a[child+1]>a[child])
        {
            child+=1;
        }
        if(a[child]>a[parent])
        {
            Swap(&a[child],&a[parent]);
            parent=child;
            child=parent*2+1;
        }
        else
        {
            break;
        }
    }
}
那么左右子树不是小堆,就不能直接使用向下调整算法了,怎么办
可以倒着从最后一颗子树开始调
从最后一个非叶子结点开始调,最后一个非叶子节点的下标是(n-1-1)/2                      
    for(i=(n-2)/2;i>=0;i--)
    {
        AdjustDown(arr,n,i);
    }

2.排序

如果我们要给数组排升续,那么我们需要建大堆

每一次向下调整都可以找出一个最大的数放在第一个位置,

我们可以把第一个和最后一个交换,然后把最后一个数(也就是找出的那个最大的数)不看作

前n-1个数,继续向下调整,选出次大的数,再跟倒数第二个位置交换,后面过程以此类推。

到最后就可以完成排序。

image.png

动图点此查看

image.png

 //建堆O(n)
 for(i=(n-2)/2;i>=0;i--)
 {
     AdjustDown(arr,n,i);
 }
 //排升序,建大堆
 int end=n-1;
 while(end>0)
 {
     Swap(&arr[0],&arr[end]);
     AdjustDown(arr,end,0);
      end--;
 }

4.完整代码

//交换两个数函数的分装
void Swap(int*x,int*y)
{
    int temp=*x;
    *x=*y;
    *y=temp;
}
//向下调整算法(左右子树必须是大堆)
void AdjustDown(int*a,int n,int root)
{
    int parent=root;
    int child=parent*2+1;
    while(child<n)
    {
        if( child+1<n && a[child+1]>a[child])
        {
            child+=1;
        }
        if(a[child]>a[parent])
        {
            Swap(&a[child],&a[parent]);
            parent=child;
            child=parent*2+1;
        }
        else
        {
            break;
        }
    }
}
#include<stdio.h>
int main()
{
    int i=0;
    int arr[]={10,9,8,7,6,5,4,3,2,1};
    int n=sizeof(arr)/sizeof(arr[0]);
    //建堆O(n)
    for(i=(n-2)/2;i>=0;i--)
    {
        AdjustDown(arr,n,i);
    }
    //排升序,建大堆
    int end=n-1;
    while(end>0)
    {
        Swap(&arr[0],&arr[end]);
        end--;
        AdjustDown(arr,end,0);
    }
    for(i=0;i<n;i++)
    {
        printf("%d ",arr[i]);
    }
    return 0;
}

5.时间复杂度的计算

用n表示元素个数

向下调整算法 ,最多向下调整高度(二叉树高度)次。

h=log(n);

所以一次向下调整的时间复杂度是log(n)

建堆的时间复杂度

T(n)=1*(h-1)+ 2* (h-2)+ 4* (h-3)+…2^(h-2)


T(n)= -h+2^h-1


建堆的时间复杂度就约等于O(N)


整体的时间复杂度O(N*logN)


相关文章
|
1月前
|
存储 算法 Java
散列表的数据结构以及对象在JVM堆中的存储过程
本文介绍了散列表的基本概念及其在JVM中的应用,详细讲解了散列表的结构、对象存储过程、Hashtable的扩容机制及与HashMap的区别。通过实例和图解,帮助读者理解散列表的工作原理和优化策略。
38 1
散列表的数据结构以及对象在JVM堆中的存储过程
|
1月前
|
存储 搜索推荐 算法
【数据结构】树型结构详解 + 堆的实现(c语言)(附源码)
本文介绍了树和二叉树的基本概念及结构,重点讲解了堆这一重要的数据结构。堆是一种特殊的完全二叉树,常用于实现优先队列和高效的排序算法(如堆排序)。文章详细描述了堆的性质、存储方式及其实现方法,包括插入、删除和取堆顶数据等操作的具体实现。通过这些内容,读者可以全面了解堆的原理和应用。
68 16
|
2月前
|
存储 JavaScript 前端开发
为什么基础数据类型存放在栈中,而引用数据类型存放在堆中?
为什么基础数据类型存放在栈中,而引用数据类型存放在堆中?
84 1
|
2月前
|
算法 搜索推荐
数据结构与算法学习十八:堆排序
这篇文章介绍了堆排序是一种通过构建堆数据结构来实现的高效排序算法,具有平均和最坏时间复杂度为O(nlogn)的特点。
74 0
数据结构与算法学习十八:堆排序
|
2月前
|
存储 算法 调度
数据结构--二叉树的顺序实现(堆实现)
数据结构--二叉树的顺序实现(堆实现)
|
2月前
|
存储 算法 分布式数据库
【初阶数据结构】理解堆的特性与应用:深入探索完全二叉树的独特魅力
【初阶数据结构】理解堆的特性与应用:深入探索完全二叉树的独特魅力
|
2月前
|
存储 算法
探索数据结构:分支的世界之二叉树与堆
探索数据结构:分支的世界之二叉树与堆
|
2月前
|
存储 算法 Java
【用Java学习数据结构系列】用堆实现优先级队列
【用Java学习数据结构系列】用堆实现优先级队列
36 0
|
2月前
|
存储 算法
【数据结构】二叉树——顺序结构——堆及其实现
【数据结构】二叉树——顺序结构——堆及其实现
|
2月前
【数据结构】大根堆和小根堆
【数据结构】大根堆和小根堆
38 0