【Algorithm】堆排,C++实现

对一个数组中的元素按照顺序构建二叉树,就形成了一个(二叉)堆。(二叉树是虚拟的,并不是真的建立二叉树)

表示堆的数组A有两个重要属性:A.heapSize,表示堆里面有多少元素,数组里有多少元素在堆里

           A.length,表示数组长度      

例如数组A= {1,2,3,4,5,6,7,8,9,10},此时A.heapSize = A.length。除了最后一层之外,这个二叉树是完满的

最大堆:父节点的值总是不小于子节点的值,反应在数组中就是A[i]>=A[2i+1] && A[i]>=A[2i+2],如果2i+2<A.size的话

最小堆:父节点的值总是不大于子节点的值,反应在数组中就是A[i]<=A[2i+1] && A[i]<=A[2i+2],如果2i+2<A.size的话,上图就是一个最小堆

堆排一般用最大堆,输出升序数组,最小堆用于优先队列。

堆排的时间复杂度是O(nlgn)

我写的是最小堆排序,输出降序数组

//=================== 最小堆维护 ==================
// 调整根节点为arr[i]的子树顺序,将最小的节点放到根节点位置
// 递归调整被置换的子节点
void minHeapfy(vector<int> &arr, int i, int heapSize){
    int left = 2 * i + 1;  //对于arr[i],它的左孩子是arr[2i+1]右孩子是arr[2i+2]
    int right = 2 * i + 2;
    int least = i;

    if (left < heapSize && arr[left] < arr[least])
        least = left;

    if (right < heapSize && arr[right] < arr[least]){
        least = right;
    }

    if (least != i){
        int temp = arr[i];
        arr[i] = arr[least];
        arr[least] = temp;
        minHeapfy(arr, least, heapSize);  //如果子树发生变动,递归调整有变动的子节点
    }
}

//=============== 建立最小堆 ================
// 利用minHeapfy调整每一棵子树,arr中arr[arrSize/2:]的元素都是叶子节点
void buildMinHeap(vector<int> &arr){
    int heapSize = arr.size();
    for (int i = heapSize/2-1; i >= 0; i--){
        minHeapfy(arr, i, heapSize);
    }
}

// ================ 输出堆排结果 ====================
//由于根节点总是全堆最小的,每次置换根节点与最后一个节点
//对被置换之前的数组进行最小堆建立
void heapSort(vector<int> &arr){
    int heapSize = arr.size();
    buildMinHeap(arr);
    for (int i = heapSize - 1; i >= 0; i--){
        int temp = arr[0]; //置换根节点元素和当前数组最后一个元素
        arr[0] = arr[i];
        arr[i] = temp;

        heapSize -= 1;
        minHeapfy(arr, 0, heapSize); //对有序元素之前的节点建立最小堆
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
    vector<int> primes = { 4, 1, 3, 2, 16, 9, 10, 14, 8, 7 };

    heapSort(primes);
    for (int i = 0; i < primes.size(); i++){
        cout << primes[i] << endl;
    }

    system("pause");
    return 0;
}
时间: 2024-10-10 02:30:21

【Algorithm】堆排,C++实现的相关文章

STL_算法_Heap算法(堆排)(精)

C++ Primer 学习中... 简单记录下我的学习过程 (代码为主) /***************************************** STL-算法--Heap算法 堆排序算法 (heapsort) make_heap()         //把容器内的数据做堆排序 push_heap()         //向堆内放入元素 pop_heap()          //删除堆顶元素 sort_heap()         //把堆排还原成普通排序 ************

堆排 归并排序 快排

堆排序的思想 利用大顶堆(小顶堆)堆顶记录的是最大关键字(最小关键字)这一特性,使得每次从无序中选择最大记录(最小记录)变得简单. 其基本思想为(大顶堆): 1)将初始待排序关键字序列(R1,R2....Rn)构建成大顶堆,此堆为初始的无序区: 2)将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,......Rn-1)和新的有序区(Rn),且满足R[1,2...n-1]<=R[n]; 3)由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,

python 快排,堆排,归并

#归并排序def mergeSort(a,L,R) :    if(L>=R) :        return    mid=((L+R)>>1)    mergeSort(a,L,mid)    mergeSort(a,mid+1,R)    p=L    q=mid+1    t=[]    while(p<=mid and q<=R) :        if a[p]<=a[q] :            t.append(a[p])            p+=

普林斯顿公开课 算法4-3:堆排

堆排的灵感源自于堆的数据结构.它是一种原地排序算法,不需要额外的临时数组. 基本思想 堆排的基本思想是: 先建立一个最大堆 将最大的元素移动到数组末尾,减小堆的大小,调整最大堆使其符合最大堆的性质 重复第二步,直到最大堆耗尽为止 第一个步骤建立最大堆的代码非常简单,只要对每个节点执行sink操作即可. 1 2 for(int k = N/2; k >= 1; k--)     sink(a, k, N); 第二个步骤也很简单,代码如下: 1 2 3 4 while(N > 1) {     e

堆排Java代码实现

堆排复习: 结论:堆排算法时间复杂度为O(nlgn),额外空间复杂度为O(1); 在开始堆排序过程之前先要熟悉两个结构 1,完全二叉树:若设二叉树的深度为h,除第 h 层外,其它各层 (1-h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树.(摘自百度百科) 大白话:说白了就是建立二叉树的过程中,二叉树每一层都是满节点的,最后一层的节点不许中间有空缺: 2,大根堆:大根堆要求根节点的关键字既大于或等于左子树的关键字值,又大于或等于右子树的关键字值.(摘自百

快排,堆排与归并排序

快排: Parition函数用于进行一次快排,本次快排将某个元素放在它应该呆在的位置pos.pos左侧全比它小,pos右侧全比它大. Parition中,设置low指针与high指针,以待排元素为标杆,判断high指向元素是否大于待排元素,若小于则与low指向的元素交换,并切换到low指针.low指针此时指向刚交换过来的元素,其一定小于待排元素,然后low自加直到low指向的元素大于待排元素,此时再与high指向的元素交换,high指向的元素为之前一次low - high交换前low指向的元素:

排序算法的实现(归并,快排,堆排,希尔排序 O(N*log(N)))

今天跟着左老师的视频,理解了四种复杂度为 O(N*log(N))的排序算法,以前也理解过过程,今天根据实际的代码,感觉基本的算法还是很简单的,只是自己写的时候可能一些边界条件,循环控制条件把握不好. //对于一个int数组,请编写一个选择冒泡算法,对数组元素排序. //给定一个int数组A及数组的大小n,请返回排序后的数组. //测试样例: //[1, 2, 3, 5, 2, 3], 6 //[1, 2, 2, 3, 3, 5] #include <iostream> using namesp

c++实现排序(简单插入,希尔,选择,快速,冒泡,堆排)

简单插入排序 适用于记录较少且基本有序的记录.算法思想:给定一个存在分界线的序列,分界线左边有序,右边无序,依次将右边的没排序的数与左边序列进行比较,插入相应位置,再对分界线做出相应调整,下面用图来说明. 代码如下: 时间复杂度:最好情况O(n),最坏O(n^2). 希尔排序 希尔排序是改进后的简单插入排序.算法思想:将序列分组排序,最后在进行一次简单插入排序. 至于如何分组,下面我将用图向大家展示 这些数的下标从0开始,即0,3 ,6,9为一组,1,4,7为一组,2,5,8为一组.也就是gap

Java常见的几种排序算法-插入、选择、冒泡、快排、堆排等

本文就是介绍一些常见的排序算法.排序是一个非常常见的应用场景,很多时候,我们需要根据自己需要排序的数据类型,来自定义排序算法,但是,在这里,我们只介绍这些基础排序算法,包括:插入排序.选择排序.冒泡排序.快速排序(重点).堆排序.归并排序等等.看下图: 给定数组:int data[] = {9,2,7,19,100,97,63,208,55,78} 一.直接插入排序(内部排序.O(n2).稳定) 原理:从待排序的数中选出一个来,插入到前面的合适位置. [java] view plain copy