堆排序及其相关操作

这里记录下堆的相关操作。

op 1:

'''
	@ data: the heap array
	@ p   : index of parent item
	@ n   : number of data
	@@ Swap p and it's son items, make p the largest of them
'''
def swapForMaxHeap(data, n, p):
	ls = p << 1 | 1
	rs = ls + 1
	# p has two sons or just left
	if ls < n  or rs < n:
		if rs < n:
			if data[ls] < data[rs]: ls = rs
		if data[p] < data[ls]:
			data[p], data[ls] = data[ls], data[p]
		return ls
	return -1

上面函数的功能,是将p所代表的父节点与其子节点的值进行比较,与节点值大的子节点交换节点值,使得父节点的值最大,并返回与其进行交换的子节点的索引。若无交换,则返回 -1.

op 2:

'''
	@ data: the heap array
	@ p   : index of parent item
	@ n   : number of data
	@@ Swap p and it's son items, make p the smallest of them
'''
def swapForMinHeap(data, n, p):
	ls = p << 1 | 1
	rs = ls + 1

	# p has two sons or just left
	if ls < n  or rs < n:
		if rs < n:
			if data[ls] > data[rs]: ls = rs
		if data[p] > data[ls]:
			data[p], data[ls] = data[ls], data[p]
			return ls
	return -1

与上面的函数类似,只是取小的结点值。

op 3:

def Swap(data, n, p, ls = 0):

	fun = {}
	fun[0] = swapForMaxHeap
	fun[1] = swapForMinHeap
	return fun[ls](data, n, p)

将上面的两个函数进行下封装,参数ls表示的是堆的类型, 0 表示大根堆, 1 表示是小根堆。

op 4:

'''
	@ data : the heap array
	@ i    : the start index to be fixUp
	@ n    : the number of data
	@ ls   : if 0, it is a max heap, otherwise, min one

	@@
'''
def fixUp(data, i, n, ls = 0):
	if n <= 1: return
	if i <= 0 or i >= n: return

	p = (i - 1) >> 1
	while p >= 0:
		Swap(data, n, p, ls)
		p = (p - 1) >> 1

结点的上溯过程,用于插入操作,插入的时候,先将新结点的值插入到堆数组的尾部,因为这个新的结点可能违反堆的性质,需要向上调整,直到调整到最顶端。

op 5:

def fixDown( data, i, n, ls = 0):
	if n <= 1: return
	if i < 0 or i >= n: return
	while i <= n - 1:
		index = Swap(data, n, i, ls)
		if index == -1: break
		i = index

结点的下沉过程,用于删除和堆的建立。删除的操作,只在堆顶进行,即删除堆顶元素,删除时,将堆的最后元素与堆顶进行交换,交换后,新的堆顶元素可能违反堆的性质,所以需要向下调整。

op 6:

'''
	@ data: data array that adjust to be heap
	@ n   : number of data
	@ ls  : 0-max heap, 1- min heap
'''
def buildHeap(data, n, ls = 0):
	if n <= 1: return
	for i in xrange( (n >> 1) - 1, -1, -1):
		fixDown(data, i, n, ls)

堆的建立其实不需要从0开始,也就是将数组中的元素一个个的插入到空的堆中,因为若没有大小堆的大小限制,给定的数组也可以视为是一种堆,只不过是杂乱无章的堆,我们只需要对这些元素进行下调整就可以了,就是从最后一个非叶子结点开始,向下调整。

op 7:

def insert(data, new_x, ls = 0):
	data.append(new_x)
	n = len( data )
	fixUp(data, n - 1, n , ls)

这就是插入操作了,插入的时候将新元素插入到最后,然后上溯,调整为符合堆的性质。

op 8:

def delete(data, n, ls = 0):
	if n <= 0: return
	if n == 1:
		del data[0]
		return
	data[0], data[-1] = data[-1], data[0]
	del data[-1]
	print data
	fixDown(data, 0, n - 1, ls)
	

删除操作允许在堆顶进行,删除后那个空缺这么办呢?身份最单调的就是最后一个结点,因为其肯定不会有孩子结点,而且也不会打乱下标,所以我们用其与堆顶交换,代码里是为了说明交换的意思,其实只要将最后结点的值赋值给堆顶就好了,即 data[ 0 ] = data[ -1]。然后删除最后一个结点。从上向下调整。

op 9:

def heapSort(data, n, ls = 0):
	if n <= 1: return
	for i in xrange(n - 1, -1, -1):
		data[i], data[0] = data[0], data[i]
		fixDown(data, 0, i, ls)
	data.reverse()
	print data

这就是堆排序的排序了,以小根堆为例,堆顶就是整个序列的最小,将其与最后的结点交换,然后调整,调整后的堆顶又是相对最小的,再交换。

堆排序及其相关操作

时间: 2024-10-13 17:11:11

堆排序及其相关操作的相关文章

STL之heap相关操作算法

说明:本文仅供学习交流,转载请标明出处,欢迎转载! 堆(heap)是一种非常重要的数据结构(这里我们讨论的是二叉堆),它是一棵满足特定条件的完全二叉树,堆的定义如下: 堆是一棵树完全二叉树,对于该完全二叉树中的每一个结点x,其关键字大于等于(或小于等于)其左右孩子结点,而其左右子树均为一个二叉堆. 在上述的定义中,若堆中父亲结点关键字的值大于等于孩子结点,则称该堆为大顶堆:若堆中父亲结点关键子的值小于等于孩子结点,则称该堆为小顶堆. 由于堆是一棵完全二叉树,所以我们可以很轻易地用一个数组存储堆中

二叉树的相关操作

#include<stdio.h> #include<malloc.h> #define MAXSIZE 20 typedef char TEelemtype; typedef struct BiTNode{ TEelemtype data; struct BiTNode *lchild,*rchild; }BiTNode,*BiTree; //队列的方式 typedef struct queueelem { BiTNode* b[MAXSIZE]; int front,rear;

(二十四)linux新定时器:timefd及相关操作函数

timerfd是Linux为用户程序提供的一个定时器接口.这个接口基于文件描述符,通过文件描述符的可读事件进行超时通知,所以能够被用于select/poll的应用场景. 一,相关操作函数 #include <sys/timerfd.h> int timerfd_create(int clockid, int flags); int timerfd_settime(int fd, int flags, const struct itimerspec *new_value, struct itim

二叉树各种相关操作(建立二叉树、前序、中序、后序、求二叉树的深度、查找二叉树节点,层次遍历二叉树等)(C语言版)

将二叉树相关的操作集中在一个实例里,有助于理解有关二叉树的相关操作: 1.定义树的结构体: 1 typedef struct TreeNode{ 2 int data; 3 struct TreeNode *left; 4 struct TreeNode *right; 5 }TreeNode; 2.创建根节点: 1 TreeNode *creatRoot(){ 2 TreeNode * root =(TreeNode *)malloc(sizeof(TreeNode)); 3 if(NULL=

linux下进程相关操作

一.定义和理解 狭义定义:进程是正在运行的程序的实例. 广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动. 进程的概念主要有两点: 第一,进程是一个实体.每一个进程都有它自己的地址空间,一般情况下,包括文本区域.数据区域和堆栈区域.文本区域存储处理器执行的代码:数据区域存储变量和进程执行期间使用的动态分配的内存:堆栈区域存储着活动过程调用的指令和本地变量. 第二,进程是一个“执行中的程序”.程序是一个没有生命的实体,只有处理器赋予程序生命时,它才能成为一个活动的实体,我们

android DataBase的相关操作(建立表结构和创建表)

先建立一个table的基类: public abstract class DbBaseTable { private static final String TAG = "DbBaseTable"; /** * @return the DB table name */ abstract String getName(); /** * Creates the DB table according to the DB scheme * * @param db */ abstract voi

WebView中的视频全屏的相关操作

最近工作中,基本一直在用WebView,今天就把它整理下: WebView 顾名思义,就是放一个网页,一个看起来十分简单,但是用起来不是那么简单的控件. 首先你肯定要定义,初始化一个webview,其实网上的例子很多,我这里就简单的把一些WebView 中可能会用到的的很重要的属性以及支持全屏播放视频该怎么实现的代码粘出来,直接放到项目中去就行了 <span style="white-space:pre"></span><pre name="co

jQuery学习笔记--JqGrid相关操作 方法列表(上)

1.获得当前列表行数:$("#gridid").getGridParam("reccount"); 2.获取选中行数据(json):$("#gridid").jqGrid('getRowData', id); 3.刷新列表:$(refreshSelector).jqGrid('setGridParam', { url: ''), postData: ''}).trigger('reloadGrid'); 4.选中行:$("#jqGrid

JQuery select控件的相关操作

本文转载于 http://www.cnblogs.com/zfc2201/archive/2012/09/06/2674312.html JQuery获取和设置Select选项方法汇总如下: 获取select 先看看下面代码: $("#select_id").change(function(){//code...}); //为Select添加事件,当选择其中一项时触发 var checkText=$("#select_id").find("option:s