二叉树学习之堆排序

认识堆是从堆排序开始的


二叉堆是完全二叉树或者是近似完全二叉树,堆存储在数组中:

根结点下标为0时,下标为n的元素的子结点下标分别为2*n+1,2*n+2,其父结点下标为(n-1)/2


二叉堆的特性:
1、父结点的键值总是>=(<=)任何一个子结点的键值

2、每个结点的左右子树都是二叉堆


当父结点的键值总是大于或等于任何一个子节点的键值时为最大堆

当父结点的键值总是小于或等于任何一个子节点的键值时为最小堆

的操作方法如下定义:

#ifndef _HEAP_CTL_H
#define _HEAP_CTL_H#ifdef __cplusplus
extern "C" {
#endifvoid heapPprint(const char *info, int a[], int nLen);
void swap(int *a, int *b);void buildMaxHeap(int *a, int hLen);
void buildMinHeap(int *a, int hLen);void minHeapAddNumber(int *a, int *nLen, int newNum);
void maxHeapAddNumber(int *a, int *nLen, int newNum);
int minHeapDelNumber(int *a, int *nLen);
int maxHeapDelNumber(int *a, int *nLen);void ascHeapSort(int *iArray,int nLen);
void descHeapSort(int *iArray,int nLen);#ifdef __cplusplus
}
#endif
#endif
函数实现如下:

#include <stdio.h>
#include "heapctl.h"static void __pprint(int a[], int i, int nLen)
{printf("(");if (i < nLen) {printf("%d", a[i]);__pprint(a, i*2+1, nLen);__pprint(a, i*2+2,nLen);}printf(")");
}/***@brief 输出堆用于tree工具来图形化显示**@params info 写在前面的话*@params a 所要打印的数组*@params nLen 数组的长度*/
void heapPprint(const char *info, int a[], int nLen)
{if (info)printf("%s", info);printf("\n\\tree");__pprint(a, 0, nLen);printf("\n");
}/***@brief 交换两个数据**@params a 用以交换的第一个数据*@params b 用以交换的第二个数据*/
void swap(int *a, int *b)
{
#if 0//利用了辅助空间tmpint tmp = *a;*a = *b;*b = tmp;
#endif#if 0//相加可能溢出*a += *b;*b = *a - *b;*a -= *b;
#endif#if 1//异或运算A^B^B=A*a ^= *b;*b ^= *a;*a ^= *b;
#endif
}/***@brief 大顶堆调整**@params A 数组A*@params hLen*@params 需要调整的节点i*/
void maxHeapAdjust(int *a,int i,int size)  //调整堆 
{int lchild=2*i+1;       //i的左孩子节点序号 int rchild=2*i+2;     //i的右孩子节点序号 int max=i;            //临时变量 if(i <= size/2)          //如果i是叶节点就不用进行调整 {if(lchild<size && a[lchild]>a[max]) {max=lchild;}    if(rchild<size && a[rchild]>a[max]) {max=rchild;}if(max != i) {swap(&a[i], &a[max]);maxHeapAdjust(a,max,size);    //避免调整之后以max为父节点的子树不是堆 }}        
}/***@brief 构建大顶堆**@params a 数组a*@params hLen 数组元素的个数*/
void buildMaxHeap(int *a, int hLen)
{int i;//堆类似完全二叉树,nLen 为偶数://深度为2的节点数n2 = nLen>>1 -1, n1 = 1, n0 = nLen>>1;//nLen 为奇数, n2 = nLen/2, n1 = 0, n0 = nLen/2+1; //n0 = n2 + 1//从非叶节点最大序号位置调整, 值为size/2 for(i=hLen/2-1; i>=0; i--){maxHeapAdjust(a,i,hLen);    }    
} /***@brief 小顶堆调整**@params A 数组A*@params hLen*@params 需要调整的节点i*/
void minHeapAdjust(int *a,int i,int size)  //调整堆 
{int lchild=2*i+1;       //i的左孩子节点序号 int rchild=2*i+2;     //i的右孩子节点序号 int max=i;            //临时变量 if(lchild<size && a[lchild]<a[max]) {max=lchild;}    if(rchild<size && a[rchild]<a[max]) {max=rchild;}if(max != i) {swap(&a[i], &a[max]);minHeapAdjust(a, max, size);    //避免调整之后以max为父节点的子树不是堆 }
}/***@brief 构建大顶堆**@params a 数组a*@params hLen 数组元素的个数*/
void buildMinHeap(int *a, int hLen)
{int i;//堆类似完全二叉树,nLen 为偶数://深度为2的节点数n2 = nLen>>1 -1, n1 = 1, n0 = nLen>>1;//nLen 为奇数, n2 = nLen/2, n1 = 0, n0 = nLen/2+1; //n0 = n2 + 1//从非叶节点最大序号位置调整, 值为size/2 for(i=hLen/2-1; i>=0; i--){minHeapAdjust(a,i,hLen);    }    
} /***@brief 向小顶堆中插入数据**@params a 要插入数据的数组*@params nLen 数组元素长度指针, 插入后会自增*@params newNum 插入的元素值**1、将插入的数据放入数组的末尾*2、根据与其父节点的大小来调整小顶堆*/ 
void minHeapAddNumber(int *a, int *nLen, int newNum)
{a[*nLen] = newNum;  int j, i = *nLen;for (j = (i-1)/2;(j >= 0 && i != 0) && a[i] < a[j];i = j, j = (i-1)/2 )swap(&a[i], &a[j]);++*nLen;    
}/***@brief 向大顶堆中插入数据**@params a 要插入数据的数组*@params nLen 数组元素长度指针, 插入后会自增*@params newNum 插入的元素值**1、将插入的数据放入数组的末尾*2、根据与其父节点的大小关系调整大顶堆*/ 
void maxHeapAddNumber(int *a, int *nLen, int newNum)
{a[*nLen] = newNum;  int j, i = *nLen;for (j = (i-1)/2;(j >= 0 && i != 0) && a[i] > a[j];i = j, j = (i-1)/2 )swap(&a[i], &a[j]);++*nLen;    
}/***@brief 小顶堆的删除操作,堆中每次都只能删除第0个数据,**@params a 要删除数据的数组*@params nLen 数组元素长度指针, 插入后会自减**1、将插入的数据放入数组的末尾*2、根据与其父节点的大小关系调整大顶堆*/ 
int minHeapDelNumber(int *a, int *nLen)
{int newLen = *nLen - 1;swap(&a[0], &a[newLen]);minHeapAdjust(a, 0, newLen);*nLen = newLen;return a[newLen];
}int maxHeapDelNumber(int *a, int *nLen)
{int newLen = *nLen - 1;swap(&a[0], &a[newLen]);maxHeapAdjust(a, 0, newLen);*nLen = newLen;return a[newLen];
}/***@brief 利用大顶堆进行升序排列**@params a 所要排序的数组名称*@params nLen 数组中元素的个数*/
void ascHeapSort(int *a,int nLen)
{int i;buildMaxHeap(a,nLen);for(i=nLen-1; i>=1; i--){swap(&a[0], &a[i]);           //交换堆顶和最后一个元素,即每次将剩余元素中的最大者放到最后面 maxHeapAdjust(a, 0, i);      //重新调整堆顶节点成为大顶堆}
} /***@brief 利用小顶堆进行降序排列**@params a 所要排序的数组名称*@params nLen 数组中元素的个数*/
void descHeapSort(int *iArray,int nLen)
{int i;buildMinHeap(iArray, nLen);for(i=nLen-1; i>=1; i--) {swap(&iArray[0], &iArray[i]);minHeapAdjust(iArray, 0, i);}
}

函数的实现方法与应用请自行参照注释

或以下文档

http://www.cnblogs.com/dolphin0520/archive/2011/10/06/2199741.html
http://blog.csdn.net/morewindows/article/details/6709644/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/508692.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

步入github世界

在源码的世界里&#xff0c;越来越多的优秀源码涌现&#xff0c;开源的世界不但代表他的优秀&#xff0c;也代表了他优秀的传播途径。 https://github.com/ github自从2008年现世&#xff0c;可谓是后来者居上。开源代码的公开库&#xff0c;优秀程序员的博客园&#xff0c;热心…

libevent学习__学习历程总结

The libevent API provides a mechanism to execute a callback function when a specific event occurs on a file descriptor or after a timeout has been reached. Furthermore, libevent also support callbacks due to signals or regular timeouts.环境搭建 下载: http:…

redis☞ python客户端

安装 https://pypi.python.org/pypi/redis/ https://github.com/andymccurdy/redis-py 参照官网,安装命令 sudo pip install redis 或者 sudo easy_install redis 亦或 源码包执行sudo python setup.py install实例 >>> import redis >>> r redis.Redis(ho…

Catalan数应用

Catalan数应用 Catalan数应用原理卡特兰数经典应用括号化买票找零组合数与阶乘计算 卡特兰数又称卡塔兰数&#xff0c;是组合数学中一个常出现在各种计数问题中的数列。由以比利时的数学家欧仁查理卡塔兰 (1814–1894)命名。 其前几项为 : 1, 2, 5, 14, 42, 132, 429, 1430,…

统计整数n的二进制表示中1的个数

(1)逐位判断&#xff08;位运算&#xff09;int counter_ones(unsigned n){int counter 0;While (n) {counter n&1;n >>1;}return counter;}(2)一个整型不为0&#xff0c;那么二进制表示时&#xff0c;至少包含一位1。如果整数减去1&#xff0c;那么最右边的1变成0…

百度2015校园招聘软件开发笔试题及答案

简单题&#xff08;本题共30分&#xff09; 请简述Tcp-ip的3次握手以及4次挥手过程&#xff1f;并解释为何关闭连接需要4次挥手(10分) 详细答案参见TCP/IP协议三次握手与四次握手流程解析 TCP三次握手、四次挥手过程如下: 通常情况下&#xff0c;一个正常的TCP连接&#xf…

python常见数据结构

Python中常见的数据结构可以统称为容器&#xff08;container&#xff09;。序列&#xff08;如列表和元组&#xff09;、映射&#xff08;如字典&#xff09;以及集合&#xff08;set&#xff09;是三类主要的容器。 一、序列&#xff08;列表、元组和字符串&#xff09; 序列…

理解‘*‘,‘*args‘,‘**‘,‘**kwargs‘

原文Understanding ‘*’, ‘*args’,’**‘and’**kwargs’ 刚开始学习python的时候&#xff0c;对有关args,kwargs,*和**的使用感到很困惑。相信对此感到疑惑的人也有很多。我打算通过这个帖子来排解这个疑惑(希望能减少疑惑)。 让我们通过以下5步来理解&#xff1a; 通过…

MongoDb随笔,PyMongo简单使用

安装MongoDb 【更新2021-07-06】 https://www.mongodb.com/try/download/community 下载对应系统的软件版本&#xff08;CentOS7.9 mongod 4.4.6&#xff09;rpm -ivh mongodb-org-server-4.4.6-1.el7.x86_64.rpm安装服务systemctl start mongod启动服务rpm -ivh mongodb-org…

python中classmethod与staticmethod的差异及应用

类中三种函数的应用 #!/usr/bin/env python # -*- coding: utf-8 -*-class TClassStatic(object):def __init__(self, data):self.data datadef printself(*arg):# for item in arg:# print item.dataprint("printself: ", arg)staticmethoddef smethod(*arg):prin…

python3元类简介(metaclass)

在Python中可以用内置函数type查看对象的类型&#xff0c;isinstance查看某个对象是某个类实例&#xff0c;通过type可以实现动态类&#xff0c;以及通过metaclass实现动态类 type()与isinstance()判断对象类型 Python 3.6.4 (v3.6.4:d48eceb, Dec 19 2017, 06:54:40) [MSC v…

linux ps 命令使用

Linux中的ps命令是Process Status的缩写。ps命令用来列出系统中当前运行的那些进程。ps命令列出的是当前那些进程的快照&#xff0c;就是执行ps命令的那个时刻的那些进程&#xff0c;如果想要动态的显示进程信息&#xff0c;就可以使用top命令。 linux上进程有5种状态 ps命令使…

UML序列图总结

序列图主要用于展示对象之间交互的顺序。 序列图将交互关系表示为一个二维图。纵向是时间轴&#xff0c;时间沿竖线向下延伸。横向轴代表了在协作中各独立对象的类元角色。类元角色用生命线表示。当对象存在时&#xff0c;角色用一条虚线表示&#xff0c;当对象的过程处于激活…

UML用例图总结

用例图主要用来描述 用户、需求、系统功能单元 之间的关系。它展示了一个外部用户能够观察到的系统功能模型图。 【用途】&#xff1a;帮助开发团队以一种可视化的方式理解系统的功能需求。 用例图所包含的元素如下&#xff1a; 1. 参与者(Actor) 表示与您的应用程序或…

动态规划--换零钱

题目描述 想兑换100元钱&#xff0c;有1,2,5,10四种钱&#xff0c;问总共有多少兑换方法 递归解法 #include<iostream> using namespace std; const int N 100; int dimes[] {1, 2, 5, 10}; int arr[N1] {1}; int coinExchangeRecursion(int n, int m) //递归…

学生表 课程表 成绩表 教师表常用SQL语句

学生表 课程表 成绩表 教师表 50个常用sql语句 建表 Student(S#,Sname,Sage,Ssex) 学生表 Course(C#,Cname,T#) 课程表 SC(S#,C#,score) 成绩表 Teacher(T#,Tname) 教师表 ---- If database exists the same name datatable deletes it. IF EXISTS(SELECT TABLE_NAME FRO…

Linux网络编程常见面试题

概述 TCP和UDP是网络体系结构TCP/IP模型中传输层一层中的两个不同的通信协议。 TCP&#xff1a;传输控制协议&#xff0c;一种面向连接的协议&#xff0c;给用户进程提供可靠的全双工的字节流&#xff0c;TCP套接口是字节流套接口(stream socket)的一种。UDP&#xff1a;用户…

sizeof与offsetof有关的结构体详解

sizeof与offsetof在程序中经常遇到&#xff0c;但在面试中其应用使得许多小伙伴吃闭门羹&#xff0c;被面试官问得哑口无言。接下来对两者的应用做详细介绍。 关于sizeof 定义 sizeof乃C/C中的一个操作符(operator), 简单的说其作用就是返回一个对象或者类型所占的内存字节数…

linux线程间同步(1)读写锁

读写锁比mutex有更高的适用性&#xff0c;可以多个线程同时占用读模式的读写锁&#xff0c;但是只能一个线程占用写模式的读写锁。 1. 当读写锁是写加锁状态时&#xff0c;在这个锁被解锁之前&#xff0c;所有试图对这个锁加锁的线程都会被阻塞&#xff1b; 2. 当读写锁在读加…

linux线程间同步(1)互斥锁与条件变量

线程的最大特点是资源的共享性&#xff0c;但资源共享中的同步问题是多线程编程的难点。linux下提供了多种方式来处理线程同步&#xff0c;最常用的是互斥锁、条件变量和信号量以及读写锁。 互斥锁(mutex) 互斥锁&#xff0c;是一种信号量&#xff0c;常用来防止两个进程或线…