每天学一点算法-堆排序算法

堆的数据结构转化为数组的定义

在起始索引为 0 的“堆”中:

1) 堆的根节点将存放在位置 0
2) 节点 i 的左子节点在位置 2 * i + 1
3) 节点 i 的右子节点在位置 2 * i + 2
4) 节点 i 的父节点在位置 floor( (i - 1) / 2 )   : 注 floor 表示“取整”操作

在起始索引为 1 的“堆”中:
1) 堆的根节点将存放在位置 1
2) 节点 i 的左子节点在位置 2 * i
3) 节点 i 的右子节点在位置 2 * i + 1

4) 节点 i 的父节点在位置 floor( i / 2 )           : 注 floor 表示“取整”操作



前人文章:http://blog.csdn.net/xiaoxiaoxuewen/article/details/7570621

堆实际上是一棵完全二叉树,其任何一非叶节点满足性质:

 Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]或者Key[i]>=Key[2i+1]&&key>=key[2i+2]

即任何一非叶节点的关键字不大于或者不小于其左右孩子节点的关键字。

堆分为大顶堆和小顶堆,满足Key[i]>=Key[2i+1]&&key>=key[2i+2]称为大顶堆,满足 Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]称为小顶堆。由上述性质可知大顶堆的堆顶的关键字肯定是所有关键字中最大的,小顶堆的堆顶的关键字是所有关键字中最小的。

重要:非叶子节点最大需要<=size/2;



根据上面的定义将图上的堆结构转换为数组后的形式为:


{11,9,10,5,8,2,6,4,3,1,7}


堆排序


定义


堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

  堆排序的平均时间复杂度为Ο(nlogn) 。


步骤

1.创建一个堆H[0..n-1]

2.把堆首(最大值)和堆尾互换

3.把堆的尺寸缩小1,并调用 shift_down (0),目的是把新的数组顶端数据调整到相应位置

4. 重复步骤2,直到堆的尺寸为1


时间复杂度


O(nlogn)


代码


package com.sprd.test.algorithm;

import java.util.ArrayList;
import java.util.List;

/**
 * Copyright 2014 TJ SPREADTRUM TEST_AF All Right Reserved
 * 
 * @author: hui.qian Created on 2014年11月26日 上午9:10:20 Description:
 */
public class Heapsort {
	static List<Integer> sortedArray = new ArrayList<Integer>();

	public void sort(int[] data) {
		if (data.length == 1) {
			sortedArray.add(data[data.length - 1]);
			return;
		}
		// 队首和堆尾互换
		int temp = 0;
		temp = data[0];
		data[0] = data[data.length - 1];
		data[data.length - 1] = temp;
		// 堆的大小减1
		int[] newData = new int[data.length - 1];
		for (int i = 0; i < newData.length; i++) {
			newData[i] = data[i];
		}
		sortedArray.add(data[data.length - 1]);
		// 重新调整堆结构

		sort(parseHeap(newData));

	}

	public int[] parseHeap(int[] raw) {
		int length = raw.length;
		for (int i = length / 2; i >= 0; i--) {
			changeHeap(raw, i, length);
		}
		return raw;
	}

	// 调整堆让其符合结构性和有序性,即让最大的值处于堆根处
	public void changeHeap(int[] raw, int i, int size) {
		int leftIndex = 2 * i + 1;
		int rightIndex = 2 * i + 2;
		int max = i;
		if (i <= size / 2) {
			if (leftIndex < size && raw[leftIndex] > raw[max]) {
				max = leftIndex;
			}
			if (rightIndex < size && raw[rightIndex] > raw[max]) {
				max = rightIndex;
			}
			if (max != i) {
				int temp = 0;
				temp = raw[max];
				raw[max] = raw[i];
				raw[i] = temp;
				changeHeap(raw, i, size);
			}
		}
	}

	public static void main(String[] args) {
		Heapsort sorter = new Heapsort();
		// int[] raw = { 11, 9, 10, 5, 8, 2, 6, 4, 3, 1, 7 };
		int[] raw = { 9, 11, 10, 5, 8, 2, 6, 4, 3, 1, 7 };
		System.out.println("调整前 : ");
		print(raw);
		raw = sorter.parseHeap(raw);
		System.out.println("排序前 : ");
		print(raw);
		long start = System.currentTimeMillis();
		sorter.sort(raw);
		long end = System.currentTimeMillis();
		System.out.println("排序后 : ");
		printList(sortedArray);
		System.out.println("耗时 : " + (end - start));
	}

	public static void print(int[] datas) {
		for (int i = 0; i < datas.length; i++) {
			System.out.print(datas[i] + " ");
		}
		System.out.println("");
	}

	public static void printList(List<Integer> datas) {
		for (int i = 0; i < datas.size(); i++) {
			System.out.print(datas.get(i) + " ");
		}
		System.out.println("");
	}

}

输出


调整前 : 
9 11 10 5 8 2 6 4 3 1 7 
排序前 : 
11 9 10 5 8 2 6 4 3 1 7 
排序后 : 
11 10 9 8 7 6 5 4 3 2 1 
耗时 : 0


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值