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 ...
随机推荐
- [PAT] A1023 Have Fun with Numbers
[题目大意] 给一个不超过20位的数字,如果将它乘以2得到的数仅仅是原来的数字重新排列得到的,那就输出Yes,下一行输出加倍后的数.如果不是,输出No,下一行输出加倍后的数. [思路] 20位过于庞大 ...
- 转:Flutter开发中踩过的坑
记录一下入手Flutter后实际开发中踩过的一些坑,这些坑希望后来者踩的越少越好.本文章默认读者已经掌握Flutter初步开发基础. 坑1问题:在debug模式下,App启动第一个页面会很慢,甚至是黑 ...
- Spring Boot源码(三):去除Tomcat
Spring boot中使用的是内置的Tomcat,而不像Spring mvc那样依赖外部tomcat运行项目. spring boot中导入了Tomcat的jar包: 点进一个Spring boot ...
- PAT (Basic Level) Practice (中文)1033 旧键盘打字 (20 分)
旧键盘上坏了几个键,于是在敲一段文字的时候,对应的字符就不会出现.现在给出应该输入的一段文字.以及坏掉的那些键,打出的结果文字会是怎样? 输入格式: 输入在 2 行中分别给出坏掉的那些键.以及应该输入 ...
- ASP.NET MVC 方法View返回的两种方式
1.参数为字符串类型 例如我们在地址栏输入http://localhost:56431/Test/Index,会查找TestController类下的Index方法并执行,如下图 当我们返回字符串类型 ...
- H5_0017:通过元素自定义属性值获取元素对象,并获取属性值
// 通过元素的属性值查找对象 // document.querySelectorAll("[data]").forEach(function(e) ...
- 关于Javascript闭包的理解
以下内容属个人理解,如有看不明白或漏洞之处,纯属水平不佳,还望见谅. 关于闭包,高程里的定义是:指有权访问另一个函数作用域中的变量的函数.创建闭包最常见的方法就是在一个函数的内部再创建一个函数. 这里 ...
- 843. n-皇后问题(dfs+输出各种情况)
n-皇后问题是指将 n 个皇后放在 n∗n 的国际象棋棋盘上,使得皇后不能相互攻击到,即任意两个皇后都不能处于同一行.同一列或同一斜线上. 现在给定整数n,请你输出所有的满足条件的棋子摆法. 输入格式 ...
- P5331 [SNOI2019]通信 [线段树优化建图+最小费用最大流]
这题真让人自闭-我EK费用流已经死了?- (去掉define int long long就过了) 我建的边害死我的 spfa 还是spfa已经死了? 按费用流的套路来 首先呢 把点 \(i\) 拆成两 ...
- R语言函数化编程笔记2
R语言函数化编程笔记2 我学过很多的编程语言,可以我写的代码很啰嗦,一定是我太懒了.或许是基础不牢地动山摇 1.为什么要学函数 函数可以简化编程语言,减少重复代码或者说面向对象的作用 2.函数 2.1 ...