C++索引从0开始的堆排序算法实现
更新2019年11月4日 04:26:35
睡不着觉起来寻思寻思干点啥吧,好像好久没写堆排了。于是写了个索引从0开始的堆排,这次把建堆函数略了并在heapsort主函数里,索引从0开始到size-1结束,长度size。
这个堆排和索引从1开始的堆排区别就是对于节点i,两个子节点分别为2i+1和2i+2。另外建堆时从索引size/2-1开始倒序维护大顶堆。下面证明下这个起始索引的节点一定对应着二叉树的最后的一个或两个叶子节点。
1.siz是偶数,那么最后一个内部节点只有左子树。siz/2-1乘2等于siz-2,siz-2加1为最后一个节点的索引,是siz-1末尾没问题。
2.siz是奇数,最后一个内部节点有左右子树。siz/2-1乘2等于((siz-1)/2-1)乘2等于siz-1-2等于siz-3,那么左子节点siz-3+1=siz-2,右子节点siz-3+2=siz-1是末尾也没问题。
void max_heap(vector<int>& nums, int i, int limit);
void heap_sort(vector<int>& nums)
{
for (int i = nums.size() / 2 - 1; i >= 0; --i) //建最大堆
{
max_heap(nums, i, nums.size());
}
for (int i = 1; i < nums.size(); ++i)
{
int temp = nums[0];
nums[0] = nums[nums.size() - i];
nums[nums.size() - i] = temp;
max_heap(nums, 0, nums.size() - i);
}
}
void max_heap(vector<int>& nums, int i, int limit)
{
int max_index = i;
if (2 * i + 1 < limit and nums[2 * i + 1] > nums[max_index])
{
max_index = 2 * i + 1;
}
if (2 * i + 2 < limit and nums[2 * i + 2] > nums[max_index])
{
max_index = 2 * i + 2;
}
if (i != max_index)
{
int temp = nums[i];
nums[i] = nums[max_index];
nums[max_index] = temp;
max_heap(nums, max_index, limit);
}
}
分割线
最近算法群里有人问堆排序的问题,我一想没想出来,就又看看算法导论堆排那章,跟着敲了一遍,感觉印象算是深刻了一些。
堆排序的几个函数:
1.maxheap(nums[ ],int i)
首先我们数组从1开始编号,为了方便。即i为父节点,nums[i]的左右孩子分别为2i和2i+1,算算对不?这个函数假设i的左右子树都已经为最大堆,只有nums[i]这个根节点可能有问题,下面上代码:
void maxheap(vector<int>& nums,int i,int limit)
//把以ri为根的子树调整为最大堆,假设其左右子树都已是最大堆
{
int largest=i;
if(2*i<=limit&&nums[i]<nums[2*i])
{
largest=2*i;
}
if(2*i+1<=limit&&nums[largest]<nums[2*i+1])
{
largest=2*i+1;
}
if(i!=largest)
{
swap(nums[i],nums[largest]);
maxheap(nums,largest,limit);
}
}
limit是数组最后一个元素的编号,看名字也看得出。函数做的事情就是先找i和他的俩孩子里最大的是哪个,如果最大的是i的其中一个孩子,那么就将其和i的值交换,这样大的就上去了,原来的nums[i]下来了,但是这个新下来的值可能与下面的左右子树构不成最大堆,此时下来的nums[i]和其新左右子树依然符合我们上面假设的条件这个函数假设i的左右子树都已经为最大堆,只有nums[i]这个根节点可能有问题,所以对其递归调用maxheap
2.createmaxheap(nums[ ]):
排序刚开始数组为无序,把它变成最大堆的函数。
代码:
void createmaxheap(vector<int>& nums)
{
int siz=nums.size();
nums.insert(nums.begin(),0);
//排序1~n
for(int i=siz/2;i>1;--i)
{
maxheap(nums,i,siz);
}
}
C的数组下标0开始的,那么我们前面插个0(插几都行),然后对1~n进行堆排序。
siz/2是最后一个非叶节点(就是编号最大的非叶节点),画个图好理解的,这就不提了。然后从这个节点开始依次往1靠,每次都把这个节点作为根节点的树变成最大堆,最后整个1~n就是最大堆了。
3.heapsort(nums[ ]):
这个更简单了:
void heapsort(vector<int>& nums)
{
createmaxheap(nums);
for(int i=nums.size()-1;i>1;--i)
{
swap(nums[1],nums[i]);
maxheap(nums,1,i-1);
}
}
先建最大堆,然后把nums[1]和nums[n]交换,然后对nums[1,n-1]继续maxheap,就是每次调整为最大堆,最大的就是第一个元素,把它和当前堆排序区间的末尾元素交换,这样循环n-1次就排好了(剩一个最小的就不用排了)。
全部代码:
C++:
#include<vector>
#include<time.h>
#include<iostream>
using namespace std;
void maxheap(vector<int>& nums,int i,int limit)
//把以ri为根的子树调整为最大堆,假设其左右子树都已是最大堆
{
int largest=i;
if(2*i<=limit&&nums[i]<nums[2*i])
{
largest=2*i;
}
if(2*i+1<=limit&&nums[largest]<nums[2*i+1])
{
largest=2*i+1;
}
if(i!=largest)
{
swap(nums[i],nums[largest]);
maxheap(nums,largest,limit);
}
}
void createmaxheap(vector<int>& nums)
{
int siz=nums.size();
nums.insert(nums.begin(),0);
//排序1~n
for(int i=siz/2;i>1;--i)
{
maxheap(nums,i,siz);
}
}
void heapsort(vector<int>& nums)
{
createmaxheap(nums);
for(int i=nums.size()-1;i>1;--i)
{
swap(nums[1],nums[i]);
maxheap(nums,1,i-1);
}
}
int main()
{
int l=100;
srand(time(NULL));
vector<int> p(l,0);
for(int i=0;i<l;++i)
{
p[i]=rand();
}
for(int i=0;i<l;++i)
{
cout<<p[i]<<" ";
}
cout<<endl<<endl;
heapsort(p);
for(int i=0;i<l;++i)
{
cout<<p[i]<<" ";
}
getchar();
}
Python:
import random
data_list=[]
for i in range(100):
data_list.append(random.uniform(1,200))
def max_heapify(data_list,i,limit):
temp=i
if 2*i<=limit and data_list[temp]>data_list[2*i]:
temp=2*i
if 2*i+1<=limit and data_list[temp]>data_list[2*i+1]:
temp=2*i+1
if temp!=i:
data_list[temp],data_list[i]=data_list[i],data_list[temp]
max_heapify(data_list,temp,limit)
def create_heap(data_list):
list_len=len(data_list)
data_list.insert(0,0)
for i in range((list_len-1)//2,0,-1):
max_heapify(data_list,i,list_len-1)
def heap_sort(data_list):
create_heap(data_list)
list_len=len(data_list)
for i in range(1,list_len-1):
data_list[1],data_list[list_len-i]=data_list[list_len-i],data_list[1]
max_heapify(data_list,1,list_len-i-1)
heap_sort(data_list)
for i in data_list:
print(i)
C++索引从0开始的堆排序算法实现的更多相关文章
- 堆排序算法 java 实现
堆排序算法 java 实现 白话经典算法系列之七 堆与堆排序 Java排序算法(三):堆排序 算法概念 堆排序(HeapSort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,可以利用数组的特 ...
- 必须知道的八大种排序算法【java实现】(三) 归并排序算法、堆排序算法详解
一.归并排序算法 基本思想: 归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的.然后再把有序子序列合并为整体有序序列. 归并 ...
- 【java排序】 归并排序算法、堆排序算法
一.归并排序算法 基本思想: 归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的.然后再把有序子序列合并为整体有序序列. 归并 ...
- Python3标准库:heapq堆排序算法
1. heapq堆排序算法 堆(heap)是一个树形数据结构,其中子节点与父节点有一种有序关系.二叉堆(binary heap)可以使用一个有组织的列表或数组表示,其中元素N的子元素位于2*N+1和2 ...
- Heapsort 堆排序算法详解(Java实现)
Heapsort (堆排序)是最经典的排序算法之一,在google或者百度中搜一下可以搜到很多非常详细的解析.同样好的排序算法还有quicksort(快速排序)和merge sort(归并排序),选择 ...
- 重新学习Mysql数据库4:Mysql索引实现原理和相关数据结构算法
本文转自互联网 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial ...
- FlipView 索引为0 WP8.1
如果使用FlipView时,出现别的页面切换到含有FlipView的页面时(缓存此页面/MainPage),点击或者滑动FlipView,Flipview自动索引到0 的问题解决办法 1.对Flipv ...
- 堆排序算法(C#实现)
在软件设计相关领域,“堆(Heap)”的概念主要涉及到两个方面: 一种是数据结构,逻辑上是一颗完全二叉树,存储上是一个数组对象(二叉堆). 另一种是垃圾收集存储区,是软件系统可以编程的内存区域. 本文 ...
- mysql索引之二:数据结构及算法原理
摘要 本文以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题.特别需要说明的是,MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,如BT ...
随机推荐
- Perl-统计文本中各个单词出现的次数(NVDIA2019笔试)
1.原题 2.perl脚本 print "================ Method 1=====================\n"; open IN,'<','an ...
- spring gzip 静态压缩优化
HTTP 压缩可以大大提高浏览网站的速度,它的原理是,在客户端请求网页后,从服务器端将网页文件压缩,再下载到客户端,由客户端的浏览器负责解压缩并浏览.相对 于普通的浏览过程HTML ,CSS,Java ...
- Python_3
""" Function_1: 寻找水仙花数. 水仙花数也被称为超完全数字不变数.自恋数.自幂数.阿姆斯特朗数, 它是一个3位数,该数字每个位上数字的立方之和正好等于它本 ...
- Uva12169 扩展欧几里得模板
Uva12169(扩展欧几里得) 题意: 已知 $x_i=(a*x_{i-1}+b) mod 10001$,且告诉你 $x_1,x_3.........x_{2t-1}$, 让你求出其偶数列 解法: ...
- 使用FRP做内网穿透
Github地址:https://github.com/fatedier/frp 什么是FRP? frp 是一个可用于内网穿透的高性能的反向代理应用,支持 tcp, udp 协议,为 http 和 h ...
- 安卓平台SQLite数据库基础操作总结
最近学了一些安卓开发,在这里分享一下SQLite数据库的使用相关部分,我使用的工具为Android Studio,后台语言为java: 首先,需要创建一个数据库辅助类DataBaseHelper,用于 ...
- shelll高级编程【实战】(1)
shell优势在于处理操作系统底层业务,2000多个命令都是shell的支持. 一键安装,报警脚本,常规业务操作,shell开发更简单快速. 1- 常用操作系统默认shell linux: Bourn ...
- Burp Suite Professional 针对APP抓包篡改数据提交【安全】
Burp Suite 是用于攻击web 应用程序的集成平台,包含了许多工具.Burp Suite为这些工具设计了许多接口,以加快攻击应用程序的过程.所有工具都共享一个请求,并能处理对应的HTTP 消息 ...
- LeetCode 第四题 Median of Two Sorted Arrays 二人 渣渣选手乱七八糟分析发现基本回到思路1
题目 There are two sorted arrays nums1 and nums2 of size m and n respectively. Find the median of the ...
- R语言函数化学习笔记4
条件语句和循环语句 当你说话时候用到了如果,此时条件出现了 举个条件函数的例子 sign_t<-function(x){ if(x>0){ return(1) }else if(x< ...