• 堆排序


    堆排序是对简单选择排序算法的一种改进。可以构建大顶堆(每个结点的值都大于等于其左右孩子的值)也可以构建小顶堆(每个结点的值都小于等于其左右孩子的值)。堆排自我感觉代码理解起来还是有点难,主要是如何构建一个新堆以及输出堆顶元素后,怎样调整剩余元素成为一个新堆。

     1、堆排代码

     1 void heapsort(SqList *s)
     2 {
     3     int increment = s->length/2;   //父结点记录,父结点为从increment到s->length的记录
     4     //构建大顶堆
     5     for (int i = increment;i>0;i--)
     6     {
     7         heapadjust(s,i,s->length);
     8     }
     9     //交换大顶堆父结点到末端,将最大元素沉到叶结点处;再调整剩余元素为一个新的大顶堆
    10     for(int j = s->length;j>1;j--)
    11     {
    12         swap(s,1,j);
    13         heapadjust(s,1,j-1);
    14     }
    15 }

    2、堆调整代码

     1 void heapadjust(SqList *s,int i,int j)
     2 {
     3     //保存当前结点
     4     int temp = s->data[i];
     5     int k;
     6     //对该节点的左右孩子进行比较,再将左右孩子中较大的与根结点比较,将最大者作为根结点(与选择排序类似,选择最大的值作为根结点)
     7     for (k = 2*i;k < j;k*=2)
     8     {
     9         if ((s->data[k]) < (s->data[k+1]))
    10         {
    11             k++;
    12         }
    13         if (temp > s->data[k])
    14         {
    15             break;
    16         }
    17         s->data[i] = s->data[k];
    18         i = k;
    19     }
    20     s->data[i] = temp;
    21 }

    堆排测试完整代码:

     1 #include <iostream>
     2 using namespace std;
     3 #define MAXSIZE 100
     4 
     5 struct SqList
     6 {
     7     int data[MAXSIZE];
     8     int length;
     9 };
    10 
    11 void heapadjust(SqList *s,int i,int j)
    12 {
    13     //保存当前结点
    14     int temp = s->data[i];
    15     int k;
    16     //对该节点的左右孩子进行比较,再将左右孩子中较大的与根结点比较,将最大者作为根结点(与选择排序类似,选择最大的值作为根结点)
    17     for (k = 2*i;k < j;k*=2)
    18     {
    19         if ((s->data[k]) < (s->data[k+1]))
    20         {
    21             k++;
    22         }
    23         if (temp > s->data[k])
    24         {
    25             break;
    26         }
    27         s->data[i] = s->data[k];
    28         i = k;
    29     }
    30     s->data[i] = temp;
    31 }
    32 
    33 void swap(SqList *s,int i,int j)
    34 {
    35     int temp;
    36     if (s->data[i] > s->data[j])
    37     {
    38         temp = s->data[i];
    39         s->data[i] = s->data[j];
    40         s->data[j] = temp;
    41     }
    42 }
    43 
    44 void heapsort(SqList *s)
    45 {
    46     int increment = s->length/2;   //父结点记录,父结点为从increment到s->length的记录
    47     //构建大顶堆
    48     for (int i = increment;i>0;i--)
    49     {
    50         heapadjust(s,i,s->length);
    51     }
    52     //交换大顶堆父结点到末端,将最大元素沉到叶结点处;再调整剩余元素为一个新的大顶堆
    53     for(int j = s->length;j>1;j--)
    54     {
    55         swap(s,1,j);
    56         heapadjust(s,1,j-1);
    57     }
    58 }
    59 
    60 void main()
    61 {
    62     SqList s;
    63     s.length = 5;
    64     int m;
    65     for (int i = 1; i <= s.length;i++)
    66     {
    67         cin >> m;
    68         s.data[i] = m;
    69     }
    70     heapsort(&s);
    71     for (int i = 1; i <= s.length;i++)
    72     {
    73         cout << s.data[i] << " ";        
    74     }
    75     system("pause");
    76 }

    结果:

    复杂度分析:

    堆排序的运行时间主要消耗在初始构建堆和重建堆时的反复筛选上。在构建堆的过程中,根结点与其左右孩子结点最多进行两次的比较与交换操作,因此整个构建堆的时间复杂度为O(n)。在正式排序的过程中,第i次取堆顶记录重建堆需要用O(logi)的时间(完全二叉树的性质),并需要取n-1次堆顶记录,因此,重建堆的时间复杂度为O(nlogn)。

    空间复杂度上,它只有一个用来交换的暂存单元,空间复杂度为O(1)。

    由于记录的比较与交换是跳跃式进行的,因此堆排是一种不稳定的排序算法。

  • 相关阅读:
    FIREDAC(DELPHI10 or 10.1)提交数据给ORACLE数据库的一个不是BUG的BUG
    分布式系统的软肋——数据一致性
    原子操作
    Android---观察者模式的简单实现demo
    Android -- 获取网络数据并将数据存到本地数据库中
    加密模式
    Vue.js——vue-resource全攻略
    VUE---Missing space before function parentheses
    css:子元素div 上下左右居中方法总结
    扒取网站的源代码
  • 原文地址:https://www.cnblogs.com/tracyhan/p/5475629.html
Copyright © 2020-2023  润新知