更新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开始的堆排序算法实现的更多相关文章

  1. 堆排序算法 java 实现

    堆排序算法 java 实现 白话经典算法系列之七 堆与堆排序 Java排序算法(三):堆排序 算法概念 堆排序(HeapSort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,可以利用数组的特 ...

  2. 必须知道的八大种排序算法【java实现】(三) 归并排序算法、堆排序算法详解

    一.归并排序算法 基本思想: 归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的.然后再把有序子序列合并为整体有序序列. 归并 ...

  3. 【java排序】 归并排序算法、堆排序算法

    一.归并排序算法 基本思想: 归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的.然后再把有序子序列合并为整体有序序列. 归并 ...

  4. Python3标准库:heapq堆排序算法

    1. heapq堆排序算法 堆(heap)是一个树形数据结构,其中子节点与父节点有一种有序关系.二叉堆(binary heap)可以使用一个有组织的列表或数组表示,其中元素N的子元素位于2*N+1和2 ...

  5. Heapsort 堆排序算法详解(Java实现)

    Heapsort (堆排序)是最经典的排序算法之一,在google或者百度中搜一下可以搜到很多非常详细的解析.同样好的排序算法还有quicksort(快速排序)和merge sort(归并排序),选择 ...

  6. 重新学习Mysql数据库4:Mysql索引实现原理和相关数据结构算法

    本文转自互联网 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial ...

  7. FlipView 索引为0 WP8.1

    如果使用FlipView时,出现别的页面切换到含有FlipView的页面时(缓存此页面/MainPage),点击或者滑动FlipView,Flipview自动索引到0 的问题解决办法 1.对Flipv ...

  8. 堆排序算法(C#实现)

    在软件设计相关领域,“堆(Heap)”的概念主要涉及到两个方面: 一种是数据结构,逻辑上是一颗完全二叉树,存储上是一个数组对象(二叉堆). 另一种是垃圾收集存储区,是软件系统可以编程的内存区域. 本文 ...

  9. mysql索引之二:数据结构及算法原理

    摘要 本文以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题.特别需要说明的是,MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,如BT ...

随机推荐

  1. 免费免驱动从网上截取正版音乐与MV及视频

    在QQ Music里听到Alan Walker 的 Songs,想download,但是要绿钻.MV也有QQ音乐的logo,这下有了一个绝佳的办法! Tools:1.Gihosoft TubeGet  ...

  2. Redis入门-01

    目录 使用场景 支持的数据类型 主从复制 原理 配置 哨兵机制 持久化 RDB(Redis Database) AOF(Append Only File) redis(Remote DIctionar ...

  3. 【Debian学徒记事】Debian快速呼出Terminal终端

    Debian快速呼出Terminal终端 书接上回,Debian已经安装完毕 失踪的Ctrl+Alt+T 安装完毕启动,我发现了剑很诡异的事,Ctrl+Alt+T居然失灵了 (在多次测试后发现,Deb ...

  4. Jquery实现挂号平台首页源码

    带二级导航.轮播海报.二级联动.搜索功能.Tab选项卡 按照国际惯例先放图 index.html <!DOCTYPE html> <html lang="zh-cn&quo ...

  5. 在 Node 中使用 formidable 处理文件上传

    具体使用方式参照官方文档:https://www.npmjs.com/package/formidable 第一:安装: # npm install --save formidable yarn ad ...

  6. java简单验证码生成程序

    下面的函数,返回的字符串就是所需验证码 public String id(){ Random ra =new Random(); st=""; String [] w= {&quo ...

  7. java学习心得2

    首先是一个生成随机数的算法 这里就需要设置种子x0,种子设置好之后就设置a,c,m,这里mod用于取余,我自己写的是这样的 这个程序可生成1000个随机数,这种随机数的生成是有上限的,可以保证在一定数 ...

  8. JavaDay9(上)

    Java learning_Day9(上) 本人学习视频用的是马士兵的,也在这里献上 <链接:https://pan.baidu.com/s/1qKNGJNh0GgvlJnitTJGqgA> ...

  9. tcp_demo

    代码讲解: server import socket def main(): # 创建tcp服务器套接字 tcp_server = socket.socket(socket.AF_INET, sock ...

  10. hyper-v虚拟机不能访问外网的解决方案

    直接说解决方案,将虚拟机的一张网卡改为旧版网络适配器即可.具体原因还不可知. 延申一下,一般应该使用的交换机,是“外部”类型即可.