堆排序

堆排序之Python实现

巧了我就是萌 提交于 2020-01-14 16:06:20
目录 python算法之堆排序 堆的概念: 堆的类型 堆排序步骤 构建完全二叉树 构建大顶堆 排序 总结 代码实现 python算法之堆排序 注意:本文中的结点和结点不加区分的使用 堆的概念: 堆是一个完全二叉树 每个非叶子结点都要大于或者等于其左右孩子结点的值称为大顶堆 每个非叶子结点都要小于或者等于其左右孩子结点的值称为小顶堆 根结点一定是大顶堆中的最大值,一定是小顶堆中的最小值 堆其实是从节点值来观察,结点值具有一点特点的完全二叉树 堆的类型 根据堆的特性,我们可以把堆分为两类 大顶堆 完全二叉树的每个非叶子结点都大于或者等于其左右孩子结点的值,根结点一定是大顶堆中的最大值, 如图1 小顶堆 每个非叶子结点都要小于或者等于其左右孩子结点的值,根结点一定是大顶堆中的最小值, 如图2 堆排序步骤 构建完全二叉树 原始数据:30,20,80,40,50,10,60,70,90 构建一个完全二叉树存放数据,并根据完全二叉树的性质5对元素编号,: 放入顺序的数据结构中构造一个列表为[0,30,20,80,40,50,10,60,70,90](插入一个0,是为了将数组的下标和完全二叉树的结点编号一致),如下图 构建大顶堆 怎么将一个队列构建成大顶堆(或者小顶堆),是堆排序的 算法核心部分 分析 1.度数为2的结点A,如果他的左右孩子结点的最大值比它大的,最大值和该结点交换 2

数据结构之二叉堆、堆排序

ぃ、小莉子 提交于 2020-01-13 13:35:11
前言 上一篇写了 数据结构之二叉搜索树、AVL自平衡树 ,这次来写堆。 堆的创造者 很久以前排序算法的时间复杂度一直是O(n^2), 当时学术界充斥着 “排序算法不可能突破O(n^2)” 的声音,直到1959年,由D.L.Shell提出了一种排序算法,希尔排序(Shell Sort),才打破了这种不可能的声音,把排序算法的时间复杂度提升到了O(n^3/2)! 当科学家们知道这种"不可能"被突破之后,又相继有了更快的排序算法,“不可能超越O(n^2)”彻底成为了历史。 在1964年,没错,是55年前! 堆排序 这种奇思妙想的,十分精彩的,排序算法诞生了!时间复杂度为O(nlogn),远甩O(n^2) 由Robert W. Floyd(罗伯特·弗洛伊德)和J.W.J. Williams(威廉姆斯)共同发明了著名的堆排序,同时也发明了“堆”这样的数据结构, Floyd在1978年获得了图灵奖!真是个狼人!!(比很人还要多一点) 有时候了解下历史,也是十分有趣的!虽然你可能会觉得并没什么卵用~ 堆是什么? 之前第一次听到 堆 这个词的时候,感觉像是一堆什么东西,完全跟树连想不到一起,后来才知道,原来 堆 也是一颗二叉树,而且是 完全二叉树 堆的性质: 堆中某个节点的值总是不大于或不小于其父节点的值; 堆总是一棵完全二叉树。 如何用数组表示堆? 我们可以把堆,存放在一个数组中

Leetcode 148: Sort List

徘徊边缘 提交于 2020-01-13 02:03:09
Sort a linked list in O ( n log n ) time using constant space complexity. Example 1: Input: 4->2->1->3 Output: 1->2->3->4 Example 2: Input: -1->5->3->4->0 Output: -1->0->3->4->5 解法一:堆排序 考虑如果被排序对象不是链表的节点,而是普通数字的情况下,此题可以用块排,堆排序等搞定。考虑到链表结构的复杂性,可以选用堆排序。将每个节点依次送入堆中,然后再从堆顶依次输出并连接成新链表即可。代码如下: public static ListNode sortList(ListNode head) { Queue<ListNode> heap = new PriorityQueue<>(new Comparator<ListNode>() { @Override public int compare(ListNode node1, ListNode node2) { if(node1.val > node2.val) { return 1 ; } else if (node1.val == node2.val) { return 0 ; } else { return -1 ; } } }) ; while(head !

优先级队列与堆排序

偶尔善良 提交于 2020-01-11 04:12:32
转自:http://www.cnblogs.com/yangecnu/p/Introduce-Priority-Queue-And-Heap-Sort.html 在很多应用中,我们通常需要按照优先级情况对待处理对象进行处理,比如首先处理优先级最高的对象,然后处理次高的对象。最简单的一个例子就是,在手机上玩游戏的时候,如果有来电,那么系统应该优先处理打进来的电话。 在这种情况下,我们的数据结构应该提供两个最基本的操作,一个是返回最高优先级对象,一个是添加新的对象。这种数据结构就是优先级队列(Priority Queue) 。 本文首先介绍优先级队列的定义,有序和无序数组以及堆数据结构实现优先级队列,最后介绍了基于优先级队列的堆排序(Heap Sort) 一 定义 优先级队列和通常的栈和队列一样,只不过里面的每一个元素都有一个”优先级”,在处理的时候,首先处理优先级最高的。如果两个元素具有相同的优先级,则按照他们插入到队列中的先后顺序处理。 优先级队列可以通过链表,数组,堆或者其他数据结构实现。 二 实现 数组 最简单的优先级队列可以通过有序或者无序数组来实现,当要获取最大值的时候,对数组进行查找返回即可。代码实现起来也比较简单,这里就不列出来了。 如上图: · 如果使用无序数组,那么每一次插入的时候,直接在数组末尾插入即可,时间复杂度为O(1),但是如果要获取最大值

堆排序

て烟熏妆下的殇ゞ 提交于 2020-01-10 16:23:46
1 #coding=utf-8 2 3 def big_endian ( arr , start , end ) : 4 root = start 5 child = root * 2 + 1 #左孩子 6 #print child 7 while child <= end : 8 if child + 1 <= end and arr [ child ] < arr [ child + 1 ] : 9 child += 1 10 if arr [ root ] < arr [ child ] : 11 arr [ root ] , arr [ child ] = arr [ child ] , arr [ root ] 12 root = child 13 child = root * 2 + 1 14 else : 15 break 16 17 18 def heap_sort ( arr ) : 19 first = len ( arr ) 20 for start in range ( first , - 1 , - 1 ) : 21 #print start 22 big_endian ( arr , start , len ( arr ) - 1 ) 23 for end in range ( len ( arr ) - 1 , 0 , - 1 ) : 24

图解堆排序

两盒软妹~` 提交于 2020-01-10 07:02:45
摘要: 作为选择排序的改进版,堆排序可以把每一趟元素的比较结果保存下来,以便我们在选择最小/大元素时对已经比较过的元素做出相应的调整。 堆排序是一种树形选择排序,在排序过程中可以把元素看成是一颗完全二叉树,每个节点都大(小)于它的两个子节点,当每个节点都大于等于它的两个子节点时,就称为大顶堆,也叫堆有序; 当每个节点都小于等于它的两个子节点时,就称为小顶堆。 (大顶堆(有序堆)) (小顶堆) 算法思想(以大顶堆为例): 1.将长度为n的待排序的数组进行堆有序化构造成一个大顶堆 2.将根节点与尾节点交换并输出此时的尾节点 3.将剩余的n -1个节点重新进行堆有序化 4.重复步骤2,步骤3直至构造成一个有序序列 假设待排序数组为[20,50,10,30,70,20,80] 构造堆 在构造有序堆时,我们开始只需要扫描一半的元素(n/2-1 ~ 0)即可,为什么? 因为(n/2-1)~0的节点才有子节点,如图1,n=8,(n/2-1) = 3 即3 2 1 0这个四个节点才有子节点 (图1:初始状态) 所以代码4~6行for循环的作用就是将3 2 1 0这四个节点从下到上,从右到左的与它自己的子节点比较并调整最终形成大顶堆,过程如下: 第一次for循环将节点3和它的子节点7 8 的元素 进行比较,最大者作为父节点(即元素60作为父节点) 【红色表示交换后的状态】 第二次 for循环

Python 堆与堆排序

我是研究僧i 提交于 2020-01-10 07:02:09
堆排序 与 快速排序 , 归并排序 一样都是时间复杂度为O(N*logN)的几种常见排序方法。学习堆排序前,先讲解下什么是数据结构中的二叉堆。 二叉堆的定义 二叉堆是完全二叉树或者是近似完全二叉树。 二叉堆满足二个特性: 1.父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。 2.每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。 当父结点的键值总是大于或等于任何一个子节点的键值时为 最大堆 。当父结点的键值总是小于或等于任何一个子节点的键值时为 最小堆 。下图展示一个最小堆: 由于其它几种堆(二项式堆,斐波纳契堆等)用的较少,一般将二叉堆就简称为堆。 堆的存储 一般都用数组来表示堆,i结点的父结点下标就为(i – 1) / 2。它的左右子结点下标分别为2 * i + 1和2 * i + 2。如第0个结点左右子结点下标分别为1和2。 堆的操作——插入删除 下面先给出《 数据结构 C++语言描述》中最小堆的建立插入删除的图解,再给出本人的实现代码,最好是先看明白图后再去看代码。 堆的插入 每次插入都是将新数据放在数组最后。可以发现从这个新数据的父结点到根结点必然为一个有序的数列,现在的任务是将这个新数据插入到这个有序数据中——这就类似于 直接插入排序 中将一个数据并入到有序区间中,对照 《白话经典算法系列之二 直接插入排序的三种实现》

堆和堆排序

大憨熊 提交于 2020-01-10 07:01:26
堆排序 与 快速排序 , 归并排序 一样都是时间复杂度为O(N*logN)的几种常见排序方法。学习堆排序前,先讲解下什么是数据结构中的二叉堆。 二叉堆的定义 二叉堆是完全二叉树或者是近似完全二叉树。 二叉堆满足二个特性: 1.父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。 2.每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。 当父结点的键值总是大于或等于任何一个子节点的键值时为 最大堆 。当父结点的键值总是小于或等于任何一个子节点的键值时为 最小堆 。下图展示一个最小堆: 由于其它几种堆(二项式堆,斐波纳契堆等)用的较少,一般将二叉堆就简称为堆。 堆的存储 一般都用数组来表示堆,i结点的父结点下标就为(i – 1) / 2。它的左右子结点下标分别为2 * i + 1和2 * i + 2。如第0个结点左右子结点下标分别为1和2。 堆的操作——插入删除 下面先给出《数据结构C++语言描述》中最小堆的建立插入删除的图解,再给出本人的实现代码,最好是先看明白图后再去看代码。 堆的插入 每次插入都是将新数据放在数组最后。可以发现从这个新数据的父结点到根结点必然为一个有序的数列,现在的任务是将这个新数据插入到这个有序数据中——这就类似于 直接插入排序 中将一个数据并入到有序区间中,对照 《白话经典算法系列之二 直接插入排序的三种实现》

面试常考的常用数据结构与算法【简】

↘锁芯ラ 提交于 2020-01-07 08:32:18
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 数据结构与算法,这个部分的内容其实是十分的庞大,要想都覆盖到不太容易。在校学习阶段我们可能需要对每种结构,每种算法都学习,但是找工作笔试或者面试的时候,要在很短的时间内考察一个人这方面的能力,把每种结构和算法都问一遍不太现实。所以,实际的情况是,企业一般考察一些看起来很基本的概念和算法,或者是一些变形,然后让你去实现。也许看起来简单,但是如果真让你在纸上或者是计算机上快速地完成一个算法,并且设计测试案例,最后跑起来,你就会发现会很难了。这就要求我们要熟悉,并牢固掌握常用的算法,特别是那些看起来貌似简单的算法,正是这些用起来很普遍的算法,才要求我们能很扎实的掌握,在实际工作中提高工作效率。遇到复杂的算法,通过分析和扎实的基本功,应该可以很快地进行开发。 闲话少说,下面进入正题。 一.数据结构部分 1. 数组和链表的区别 。(很简单,但是很常考,记得要回答全面) C++语言中可以用 数组 处理一组数据类型相同的数据,但 不允许动态定义数组的大小 ,即在使用数组之前必须确定数组的大小。而在实际应用中,用户使用数组之前有时无法准确确定数组的大小,只能将数组定义成足够大小,这样数组中有些空间可能不被使用,从而 造成内存空间的浪费 。 链表是一种常见的数据组织形式,它采用动态分配内存的形式实现 。需要时可以用

C/C++版数据结构之排序算法

柔情痞子 提交于 2020-01-03 05:17:59
今天讨论下数据结构中的排序算法。 排序算法的相关知识: (1)排序的概念:所谓排序就是要整理文件中的记录,使之按关键字递增(或递减)次序排列起来。 (2)稳定的排序方法:在待排序的文件中,若存在多个关键字相同的记录,经过排序后这些具有相同关键字的记录之间的相对次序保持不变,该排序方法是稳定的。相反,如果发生改变,这种排序方法不稳定。 (3)排序算法的分类(分为5类):插入排序、选择排序、交换排序、归并排序和分配排序。 (4)排序算法两个基本操作:<1>比较关键字的大小。 <2>改变指向记录的指针或移动记录本身。 具体的排序方法: 插入排序 <1>插入排序(Insertion Sort)的思想:每次将一个待排序的记录按其关键字大小插入到前面已经排好序的子记录中的适当位置,直到全部记录插入完成为止。 <2>常用的插入排序方法有直接插入排序和希尔排序。 (1)直接插入排序 <1>算法思路:把一个记录集(如一个数组)分成两部分,前半部分是有序区,后半部分是无序区;有序区一开始有一个元素r[0],无序区一开始是从r[1]到之后的所有元素;然后每次从无序区按顺序取一个元素r[i],拿到有序区中由后往前进行比较,每次比较时,有序区中比r[i]大的元素就往后移动一位,直到找到小于r[i]的元素,这时r[i]插到小元素的后面,则完成一趟直接插入排序。如此反复,从无序区不断取元素插入到有序区