堆排序-学习笔记

在学习堆排序之前首先了解一下二叉堆的特性:

1、二叉堆的父节点的值总是大于等于(或小于等于)其左右孩子的值;

2、每个节点的左右子树都是一棵这样的二叉堆。

如果该二叉堆的父节点总是大于孩子节点,则叫做最大堆,如果父节点小于孩子节点,则叫做最小堆。

在堆排序的应用中,如果递增排序,则应该使用最大堆,反之,使用最小堆。

堆排序是不稳定的

堆排序主要有两个步骤来完成堆排序:

1、把一个无序数列构造成一个最大堆或最小堆;

2、去掉根节点(堆顶元素),把剩下的元素重新构造一个二叉堆。

二叉堆的存储结构为一维数组,逻辑结构为二叉树。

在一个索引以0为开头的数组中,i为二叉堆的非叶子节点,它的左孩子为2*i+1,右孩子为2*i+2 ,他的父节点为(i-1)/2。

构造二叉堆:

1、选取最后一个非叶子节点,和他的左右孩子比较,如果有大于(小于)父节点的,则把左右孩子节点中较大的一个与父节点对换。

2、重复上述步骤,直到所有的节点全部扫描一遍,这样,二叉堆就构造好了。

调整二叉堆:

1、把堆顶元素和最后一个元素互换,构成了一个新的数组 a[0...n-1];

2、把新构成二叉堆重新扫描,因为只是更换了堆顶元素,所以只要扫描堆顶元素就可以了,完成后,构成了一个新的二叉堆。

3、重复上述步骤,直到二叉堆内的元素为1;

4、最后,新构成的数组就是排好序的了。

代码如下

#include<cstdio>

void HeapadjustDown(int a[],int _begin,int _end){ //二叉堆构造函数
    int temp=a[_begin];    //把节点保存在临时temp里
    int lchild=2*_begin+1; //lchild为左孩子
    while(lchild<_end){ //循环控制条件
        if(lchild+1<_end&&a[lchild+1]>a[lchild]){ //从左右孩子中选取最大的
            lchild++;
        }
        if(a[lchild]<temp){ //如果左右孩子节点都比父节点小,则退出
            break;
        }
        a[_begin]=a[lchild];//父节点被子节点替换
        _begin=lchild;//把当前父节点设置为替换的孩子节点
        lchild=2*_begin+1;//重新设置左孩子节点
    }
    a[_begin]=temp;//把最开始的父节点赋值到,孩子节点中。

}

void HeapSort(int a[],int n){
    for(int i=(n-1)/2;i>=0;i--){//这个循环是构造二叉堆
        HeapadjustDown(a,i,n);
    }
    for(int i=n-1;i>=0;i--){//这个循环是构造有序数组
        int temp=a[i];
        a[i]=a[0];
        a[0]=temp;
        HeapadjustDown(a,0,i);//去掉堆顶元素后,重新构造二叉堆
    }
}
int main(){
    int n,a[20];
    scanf("%d",&n);
    for(int i=0;i<n;i++){

        scanf("%d",&a[i]);
    }
    HeapSort(a,n);
    for(int i=0;i<n;i++){
        printf("%d ",a[i]);
    }
}
时间: 2024-10-07 21:48:05

堆排序-学习笔记的相关文章

【算法导论】学习笔记——第6章 堆排序

堆这个数据结构应用非常广泛,数字图像处理的算法里也见过.似乎记得以前老师上课说需要用树结构实现堆排序,看了一下算法导论才明白其精髓.堆虽然是一棵树,但显然没必要非得用树结构实现堆排序.堆排序的性质很好,算法时间复杂度为O(nlgn). 1. 堆排序的简要说明.二叉堆可以分为两种形式:最大堆和最小堆.在最大堆中,最大堆性质是指除了根以外的所有结点i都要满足: A[PARENT(i)] >= A[i]:在最小堆中,最小堆性质是指除了根以外的所有结点i都要满足: A[PARENT(i)] <= A[

java排序学习笔记

前面写了js的排序实现,总得玩玩java的哈. 同样,冒泡.选择.快速(这三个之前实现过也写过文章).堆排序,然后做比较. 主要遇到的难点: - -||想轻松点写个封装计时的逻辑,不想每调用一个排序就要写一个计时代码.想想,还是javascript写起来方便: java的话,我想到的方法是写一个抽象类:抽象出排序方法,实现一个排序计时方法(该方法调用了抽象排序,但在先后排序时加入计时代码[感觉像是aop操作]): 接着所有排序类都继承这个抽象类,并实现排序方法,调用的时候直接调用继承的排序计时方

《大话数据结构》学习笔记 排序

排序的严格定义:  假设含有n个记录的序列为{r1,r2,......,rn},对应的关键字分别为{k1,k2......,kn},需确定1,2,......,n的一种排列p1,p2,......,pn,使其相应的关键字 满足Kp1<=Kp2<=......Kpn关系,即使得序列成为一个按关键字有序的序列(rpq,rp2,......rpn),此操作称为排序.  排序的稳定性:内排序与外排序(根据记录是否全部放置在内存中). 根据排序中的主要操作,可以分为插入排序类(直接插入排序->希尔

[学习笔记]数据结构与算法

1.排序简单排序:?冒泡排序:将n个数从上往下排列,从第0个数开始依次对前n个.前n-1个.前n-2个数进行比较,保持小数在前大数在后,不符合就交换.在这个过程中,最后一个数始终是最大数.?选择排序:对所有n个.后n-1个.后n-2个依次比较,用一个变量存最小数,一趟比较完成之后,将最小数与所比较数据的第一个数进行交换.在这个过程中,第一个数始终是最小数.?插入排序:从第1个数开始向前扫描比较,小则插入.对于未排序数据,在已排序序列中向前扫描,并找到相应的位置插入.在这个过程中,整个序列局部有序

Android学习笔记-回顾计划

人最怕的是,没有方向! 1.楔子: 本人接触Andrjoid开发也有一年多了,期间在一家外包公司独立开发了五六个项目.虽谈不上大牛,但自认小有所成.平时没什么爱好,就喜欢看看技术博客,试验各种开源代码,写写学习笔记. 最近感觉有点陷入瓶颈了,进步甚慢,却又不知该如何进一步提升自己.对于开发中遇到的很多问题,虽有所领悟,然不够系统,一些小知识点,也常有遗漏.觉得是时候系统的反思一下自己的知识体系了,于是决定制定一个回顾计划,综合自己看的博客.书籍,以及自己的开发实践,对一些常用的知识点进行整理.

数据结构与算法基础学习笔记

*********************************************            ---算法与数据机结构--- 数据结构:由于计算机技术的发展,需要处理的对象不再是纯粹的数值,还有像字符,表,图像等具有一定结构的数据,需要用好的算法来处理这些数据. 我们把现实中大量而又复杂的问题以特定的数据类型的特定的存储结构保存到主存储器中,以及在此基础上为实现某个功能而执行的相应操作(查找排序),这个相应的操作也叫算法. 数据结构 = 个体 +个体的关系算法 =对存储数据的操

vector 学习笔记

vector 使用练习: /**************************************** * File Name: vector.cpp * Author: sky0917 * Created Time: 2014年04月27日 11:07:33 ****************************************/ #include <iostream> #include <vector> using namespace std; int main

Caliburn.Micro学习笔记(一)----引导类和命名匹配规则

Caliburn.Micro学习笔记(一)----引导类和命名匹配规则 用了几天时间看了一下开源框架Caliburn.Micro 这是他源码的地址http://caliburnmicro.codeplex.com/ 文档也写的很详细,自己在看它的文档和代码时写了一些demo和笔记,还有它实现的原理记录一下 学习Caliburn.Micro要有MEF和MVVM的基础 先说一下他的命名规则和引导类 以后我会把Caliburn.Micro的 Actions IResult,IHandle ICondu

jQuery学习笔记(一):入门

jQuery学习笔记(一):入门 一.JQuery是什么 JQuery是什么?始终是萦绕在我心中的一个问题: 借鉴网上同学们的总结,可以从以下几个方面观察. 不使用JQuery时获取DOM文本的操作如下: 1 document.getElementById('info').value = 'Hello World!'; 使用JQuery时获取DOM文本操作如下: 1 $('#info').val('Hello World!'); 嗯,可以看出,使用JQuery的优势之一是可以使代码更加简练,使开