加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Python > 正文

Python堆排序原理与实现方法详解

发布时间:2020-12-16 21:05:24 所属栏目:Python 来源:网络整理
导读:本篇章节讲解Python堆排序原理与实现方法。供大家参考研究具体如下: 在这里要事先说明一下我也是新手,很多东西我了解不是很深入,写算法完全是锻炼自己逻辑能力同时顺带帮助读研的朋友么解决一些实际问题。所以很多时候考虑的东西不是很全面能请

本篇章节讲解Python堆排序原理与实现方法。分享给大家供大家参考,具体如下:

在这里要事先说明一下我也是新手,很多东西我了解不是很深入,写算法完全是锻炼自己逻辑能力同时顺带帮助读研的朋友么解决一些实际问题。所以很多时候考虑的东西不是很全面能请各位看到博文的大牛们指正。对于排序算法说实在的我觉得已经写烂了,但是为什么还是要过一遍呢?还是为了能够打牢基础。说一下自己的看法,对于已经的玩烂的算法因该怎么学。首先最重要的还是了解算法的基本模型和算法思想,我觉得这是非常重要的。其次的话首先先尝试自己实现算法每个步骤的功能,当遇到瓶颈的时候回去看算法思想。当你写出来的时候就应该去网上找找有没有更好的实现方法。编程最大的魅力在于每个人都有每个人的套路。然后去思考自己还有哪些地方写的不够好。写算法实际上目标只有两个,对基础语法的巩固和对算法思想的理解。

堆排序

在这里首先要先解释一下什么是堆,堆栈是计算机的两种最基本的数据结构。堆的特点就是FIFO(first in first out)先进先出,这里的话我觉得可以理解成树的结构。堆在接收数据的时候先接收的数据会被先弹出。

栈的特性正好与堆相反,是属于FILO(first in/last out)先进后出的类型。栈处于一级缓存而堆处于二级缓存中。这个不是本文重点所以不做过多展开。

堆排序节点访问和操作定义

堆节点的访问

在这里我们借用wiki的定义来说明:

通常堆是通过一维数组来实现的。在阵列起始位置为0的情况中

(1)父节点i的左子节点在位置(2*i+1);
(2)父节点i的右子节点在位置(2*i+2);
(3)子节点i的父节点在位置floor((i-1)/2);

堆操作

堆可以分为大根堆和小根堆,这里用最大堆的情况来定义操作:

(1)最大堆调整(MAX_Heapify):将堆的末端子节点作调整,使得子节点永远小于父节点。这是核心步骤,在建堆和堆排序都会用到。比较i的根节点和与其所对应i的孩子节点的值。当i根节点的值比左孩子节点的值要小的时候,就把i根节点和左孩子节点所对应的值交换,当i根节点的值比右孩子的节点所对应的值要小的时候,就把i根节点和右孩子节点所对应的值交换。然后再调用堆调整这个过程,可见这是一个递归的过程。

(2)建立最大堆(Build_Max_Heap):将堆所有数据重新排序。建堆的过程其实就是不断做最大堆调整的过程,从len/2出开始调整,一直比到第一个节点。

(3)堆排序(HeapSort):移除位在第一个数据的根节点,并做最大堆调整的递归运算。堆排序是利用建堆和堆调整来进行的。首先先建堆,然后将堆的根节点选出与最后一个节点进行交换,然后将前面len-1个节点继续做堆调整的过程。直到将所有的节点取出,对于n个数我们只需要做n-1次操作。

这里用网上的一张直观图来感受一下

代码:

# -*- coding: utf-8 -*-
#! python2
import random
def MAX_Heapify(heap,HeapSize,root):#在堆中做结构调整使得父节点的值大于子节点
  left = 2*root + 1
  right = left + 1
  larger = root
  if left < HeapSize and heap[larger] < heap[left]:
    larger = left
  if right < HeapSize and heap[larger] < heap[right]:
    larger = right
  if larger != root:#如果做了堆调整则larger的值等于左节点或者右节点的,这个时候做对调值操作
    heap[larger],heap[root] = heap[root],heap[larger]
    MAX_Heapify(heap,larger)
def Build_MAX_Heap(heap):#构造一个堆,将堆中所有数据重新排序
  HeapSize = len(heap)#将堆的长度当独拿出来方便
  for i in xrange((HeapSize -2)//2,-1,-1):#从后往前出数
    MAX_Heapify(heap,i)
def HeapSort(heap):#将根节点取出与最后一位做对调,对前面len-1个节点继续进行对调整过程。
  Build_MAX_Heap(heap)
  for i in range(len(heap)-1,-1):
    heap[0],heap[i] = heap[i],heap[0]
    MAX_Heapify(heap,i,0)
  return heap
if __name__ == '__main__':
  a = [30,50,57,77,62,78,94,80,84]
  print a
  HeapSort(a)
  print a
  b = [random.randint(1,1000) for i in range(1000)]
  print b
  HeapSort(b)
  print b

运行结果:

[30,84]
[30,84,94]
[107,115,207,919,128,651,534,546,217,295,54,202,498,620,174,897,873,112,729,588,669,994,773,462,550,347,597,440,426,271,677,323,302,604,154,589,871,235,305,502,743,575,53,130,686,726,959,980,884,542,246,292,226,608,357,229,168,415,671,972,142,472,375,522,486,241,368,839,841,137,545,427,601,476,757,136,506,394,975,162,163,26,776,886,82,37,248,47,23,895,623,373,147,109,553,176,204,530,927,656,153,487,113,20,334,554,850,510,423,795,403,499,509,531,256,920,313,694,322,100,825,578,954,526,92,820,9,931,303,408,132,833,194,902,766,14,140,328,636,316,536,232,687,425,811,432,955,715,339,861,736,411,901,609,353,97,330,896,852,1000,828,5,879,41,642,719,35,621,742,285,987,641,993,319,647,555,436,479,85,899,556,71,237,189,211,106,164,371,730,679,491,981,372,483,676,125,868,903,33,710,199,835,458,311,384,81,784,338,3,665,934,362,122,816,2,439,869,806,760,309,360,61,756,995,652,735,894,745,654,734,699,933,59,758,753,195,527,281,321,681,858,877,278,966,706,947,648,893,247,882,859,675,243,129,424,475,478,946,720,881,737,470,252,921,382,659,441,854,134,116,183,840,661,916,496,888,70,600,998,457,707,572,950,111,320,181,796,731,892,629,539,58,173,126,922,381,63,633,723,628,582,379,831,863,245,49,419,713,887,399,698,280,220,764,782,974,912,939,949,99,481,885,907,201,21,213,242,172,627,996,957,386,788,643,200,646,32,722,370,904,393,74,42,948,428,155,708,936,819,763,596,467,31,631,540,909,809,832,88,240,598,337,552,611,693,518,397,849,15,438,133,771,412,619,711,383,310,139,870,98,712,637,350,261,443,152,690,52,45,684,655,778,405,8,640,236,579,43,595,225,188,890,846,794,682,649,569,614,986,800,563,266,156,231,696,914,358,538,770,13,960,768,119,602,807,622,359,209,314,590,275,775,785,557,680,905,406,932,348,812,891,214,171,296,279,668,335,345,541,997,732,525,612,704,511,505,818,815,689,978,721,824,277,838,16,910,332,301,727,851,395,864,400,990,75,969,823,378,489,222,269,984,493,182,822,664,167,956,454,46,537,374,497,787,577,187,862,392,430,853,566,366,962,929,123,484,331,55,341,86,414,288,464,513,573,697,988,376,56,482,701,709,420,524,692,516,576,942,265,826,769,843,387,91,352,660,208,570,377,724,349,317,953,599,615,93,926,447,928,312,667,298,18,170,657,532,263,480,898,923,51,786,733,471,703,983,19,145,781,565,258,4,634,560,691,875,291,562,249,638,653,805,717,273,230,452,755,44,431,610,450,179,326,523,917,845,714,924,865,239,971,433,814,442,564,485,867,404,83,210,270,264,283,1,521,804,494,260,543,409,299,416,945,672,547]
[1,107,547,1000]

这里的函数名我就直接用了wiki上对堆操作的定义,方便理解,其实也是方便我以后来看。

时间复杂度

堆排序的时间复杂度分为两个部分一个是建堆的时候所耗费的时间,一个是进行堆调整的时候所耗费的时间。而堆排序则是调用了建堆和堆调整。

刚刚在上面也提及到了,建堆是一个线性过程,从len/2-0一直调用堆调整的过程,相当于o(h1)+o(h2)+…+o(hlen/2)这里的h表示节点深度,len/2表示节点深度,对于求和过程,结果为线性的O(n)

堆调整为一个递归的过程,调整堆的过程时间复杂度与堆的深度有关系,相当于lgn的操作。

因为建堆的时间复杂度是O(n),调整堆的时间复杂度是lgn,所以堆排序的时间复杂度是O(nlgn)

PS:这里再为大家推荐一款关于排序的演示工具供大家参考:

在线动画演示插入/选择/冒泡/归并/希尔/快速排序算法过程工具:
http://tools.aspzz.cn/aideddesign/paixu_ys

更多关于Python相关内容感兴趣的读者可查看本站专题:《Python数据结构与算法教程》、《Python列表(list)操作技巧总结》、《Python编码操作技巧总结》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》及《Python入门与进阶经典教程》

希望本文所述对大家Python程序设计有所帮助。

您可能感兴趣的文章:

  • python 实现堆排序算法代码
  • Python实现堆排序的方法详解
  • python下实现二叉堆以及堆排序的示例
  • Python实现基于二叉树存储结构的堆排序算法示例
  • Python排序搜索基本算法之堆排序实例详解
  • Python实现的堆排序算法原理与用法实例分析
  • Python实现的堆排序算法示例
  • python冒泡排序算法的实现代码
  • python快速排序代码实例
  • python 实现插入排序算法

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读