(高效率排序算法三)堆排序

一.堆的介绍

        动态效果图

       

堆有如下特点的二叉树:

1.他是完全的二叉树。也就是说,除了树的最后一层布需要时满的,其他的每一层从左到右都是满的.(如下图的完全二叉树跟不完全二叉树)

2.它常常用一个数组在实现。(如下图显示了堆它与数组之间的关系。堆在存储器中的表示是数组;堆只是概念上的表示。注意树是完全二叉树,并且所有的节点满足堆的条件)

3.堆中的每一个节点都满足堆的条件,也就是说每一个节点的值都大于或者等于这个节点的子节点的值(如上图)

二,堆的移除

1.只能移除根

2.把最后一个节点移动到根的位置

3.一直向下筛选这个节点,直到它在一个大于它的节点之下,小于它的节点之上

如下图:

不过要注意向下筛选选择较大子节点交换位置如下图

三.堆的插入

1节点初始化插入数组最后一个空的位置,使用向上筛选(目标节点只用跟它的父节点比较)

如下图

四.不是真的交换

不管是堆插入节点还是删除节点都不真的交换,如下图:在三次交换后A在D的位置上,B,C,D向上移动一位,a图中异常交换使用3次复杂,3次交换就是9次复杂。而b图中总共才使用5次复制。所以很明显我们使用b图的方式

四.堆节点的特征

若数组的某节点索引值为x那么:

1.它的父节点的下标为(x-1)/2

2.它的左子节点下标为2*x+1

3.它的右子节点下标为2*x+2

五.堆排序算法

堆的数据结构引出了很有效率的排序算法,称为堆排序算法

排序过程中使用同一数组如下图

六,堆排序的java代码

package data;

import java.util.Arrays;
import java.util.Random;

/**
 * 堆排序
 * @author JYC506
 *
 */
public class HeapSort {

	public static void sort(int[] arr){
		Heap heap=new Heap(arr.length);
		for(int i=0;i<arr.length;i++){
			heap.insert(arr[i]);
		}
		for(int i=arr.length-1;i>-1;i--){
			arr[i]=heap.remove();

		}
	}

	public static void main(String[] args) {
		/*创建堆*/
		  int num=10;
          Heap heap=new Heap(num);
          int[] arr=new int[num];
          Random ran=new Random();
          for(int i=0;i<num;i++){
        	  int data= ran.nextInt(num);
        	  heap.insert(data);
        	  arr[i]=data;
          }
          System.out.println(heap);
          for(int i=0;i<num;i++){
        	 System.out.println("移除出来的数据:"+heap.remove());
          }
         System.out.println("移除完所有数据后的堆里面的数组的情况:"+heap);
         /*直接用堆排序*/
         System.out.println("堆排序前:"+Arrays.toString(arr));
         HeapSort.sort(arr);
         System.out.println("堆排序后:"+Arrays.toString(arr));
	}
}
/**
 * 堆
 *
 */
class Heap {
    /*当前存储空间*/
	private int[] arr;
    /*最大的范围*/
	private int maxSize;
    /*现在的大小*/
	private int currentSize;

	public Heap(int maxSize) {
		this.maxSize = maxSize;
		this.currentSize = 0;
		this.arr = new int[maxSize];
	}

	public int remove() {
		int data = arr[0];
		/*移除根并且把最后一个节点移动到跟的位置,大小减一*/
		this.arr[0] = arr[--currentSize];
		/*渗透*/
		this.trickleDown(0);
		/*删除的部分使用同一数组*/
		arr[this.currentSize]=data;
		return data;
	}

	public boolean insert(int data) {
		if (currentSize == maxSize) {
			return false;
		}
		arr[currentSize] = data;
		/*冒泡*/
        this.trickleUp(currentSize++);
		return true;
	}
    /*插入数据时冒泡*/
	private void trickleUp(int index) {
		int parent = (index - 1) / 2;
		int buttom = arr[index];
		/*当有父节点时*/
		while (index > 0 && arr[parent] < buttom) {
			arr[index] = arr[parent];
			index=parent;
			parent = (parent - 1) / 2;
		}
		arr[index] = buttom;
	}
    /*删除数据时候渗透*/
	private void trickleDown(int index) {
		int largerChild;
		int top = arr[index];
		/*当有子节点*/
		while (index < this.currentSize / 2) {
			int leftChild = 2 * index + 1;
			int rightChild = leftChild + 1;
			if (rightChild < currentSize && arr[leftChild] < arr[rightChild]) {
				largerChild = rightChild;
			} else {
				largerChild = leftChild;
			}
			if (top > arr[largerChild]) {
				break;
			}
			arr[index] = arr[largerChild];
			index = largerChild;
		}
		arr[index] = top;
	}

	@Override
	public String toString() {
		return "Heap [arr=" + Arrays.toString(arr) + "]";
	}

	public int[] getArr() {
		return arr;
	}

}

运行结果如下

时间: 2024-08-04 18:45:35

(高效率排序算法三)堆排序的相关文章

排序算法(三)之堆排序

预备知识 堆排序 堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为O(nlogn),它也是不稳定排序.首先简单了解下堆结构. 堆 堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆:或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆.如下图: 同时,我们对堆中的结点按层进行编号,将这种逻辑结构映射到数组中就是下面这个样子 该数组从逻辑上讲就是一个堆结构,我们用简单的公式来描述一下堆的定义就是: 大顶

排序算法系列——堆排序

记录学习点滴,菜鸟成长记 堆排序引入了另一种算法设计技巧:使用一种我们称之为“堆”的数据结构来进行数据管理. 堆排序算是真正意义上的利用数据结构来求解数组排序的方法. “插入排序”和“归并排序”可以看做是一种“计算机体力活”,体现的思想更多的是去模拟最简单的人类思维,比如插入排序过程中的比较,归并中子问题合并时的比较. “堆排序”可以看做是“计算机脑力活”,他利用了一种结构化的语言来表达,这种结构化带来一些性质,比如左右孩子.比[堆大小的一半向下取整]大的下标都是叶节点不需要维护其最大堆性质等.

排序算法三:堆排序(Heapsort)

堆排序(Heapsort)是一种利用数据结构中的堆进行排序的算法,分为构建初始堆,减小堆的元素个数,调整堆共3步. (一)算法实现 1 protected void sort(int[] toSort) { 2 buildHeap(toSort); 3 for (int i = toSort.length - 1; i > 0; i--) { 4 CommonUtils.swap(toSort, 0, i); 5 adjustHeap(toSort, 0, i); 6 } 7 } 8 9 /**

排序算法之堆排序(Heapsort)解析

一.堆排序的优缺点(pros and cons) (还是简单的说说这个,毕竟没有必要浪费时间去理解一个糟糕的的算法) 优点: 堆排序的效率与快排.归并相同,都达到了基于比较的排序算法效率的峰值(时间复杂度为O(nlogn)) 除了高效之外,最大的亮点就是只需要O(1)的辅助空间了,既最高效率又最节省空间,只此一家了 堆排序效率相对稳定,不像快排在最坏情况下时间复杂度会变成O(n^2)),所以无论待排序序列是否有序,堆排序的效率都是O(nlogn)不变(注意这里的稳定特指平均时间复杂度=最坏时间复

排序算法: 堆排序法

一,使用堆排序法之前,需要了解堆的特性: 1,堆一般都用数组的方式来存储,堆分为“最大堆”和“最小堆”: 2,以“最大堆”为例: (1)一个节点最多有两个子节点,即左右节点,每个节点都是一个堆: (2)父节点的值不小于子节点的值: (3)一个i节点,其父节点为(i-1)/2,左节点(2*i+1),右节点(2*i+2) 一个最大堆例子: 数组 int a[]: 83 78 81 48 17 27 二,将一个数组形成堆(以最大堆为例) 数组a[]: 27 48 81 78 17 83 形成最大堆思路

(高效率排序算法一)并归排序

归并排序 归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用.将已有序的子序列合并,得到完全有序的序列:即先使每个子序列有序,再使子序列段间有序.若将两个有序表合并成一个有序表,称为二路归并. 归 并过程为:比较a[i]和a[j]的大小,若a[i]≤a[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1:否则将第二 个有序表中的元素a[j]复制到r[k]中,并令j和k分别加上1,如此循环下去,直

常用算法之排序算法三【快速排序】

快速排序是东尼·霍尔在1962提出的划分交换排序,并采用一种分治的策略.在这,我们先总结一下:快速排序 = 划分交换排序 + 分治.然后我们在一一介绍他. 划分交换排序 在讨论它时,感觉有种看了崔颢<黄鹤楼>之后,再去写黄鹤楼的感觉,因为MoreWindows写 得白话经典算法系列之六 快速排序 快速搞定已经足够出色了.我在这只是进行简单的复述,你需要了解更多请看他的博文. 先来看看划分交换排序的具体算法描述: 1.从数列中选出一个数作为基准 2.从数组中选出比它大的数放右边,比它小的数放左边

常用排序算法(三)直接插入排序

直接插入排序 概要 本章介绍排序算法中的直接插入排序.内容包括:1. 直接插入排序介绍2. 直接插入排序图文说明3. 直接插入排序的时间复杂度和稳定性4. 直接插入排序实现4.1  直接插入排序C实现4.2  直接插入排序C++实现4.3  直接插入排序Java实现 转载请注明出处:http://www.cnblogs.com/skywang12345/p/3596881.html 更多内容:数据结构与算法系列 目录 直接插入排序介绍 直接插入排序(Straight Insertion Sort

排序算法之堆排序

1. 堆排序的思想 输入一个数组,利用一组二叉树的操作使其变成有序的数组,就是堆排序 堆排序利用的是二叉树的思想,操作对象是数组,所以数组需要在逻辑上映射到二叉树上,由于数组的下标是连续的,而二叉树中只有完全二叉树和满二叉树是连续的,所以将数组元素逐个映射到完全二叉树上,然后配备一系列的操作即可.例如数组data[]={9,6,5,4,3,2,1,7},映射到完全二叉树上如下图所示. 2.堆排序的过程 还是用上面的data数组作为输入数组,映射到完全二叉树如上图所示,怎么利用二叉树的性质,才能使