Java 堆排序算法 和 快速排序算法的效率比较

堆排序算法 与 快速排序算法 的运行效率比较

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

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

算法步骤:算法

建立一个堆H[0…n-1]数组

把堆首(最大值)和堆尾互换数据结构

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

  2. 重复步骤2,直到堆的尺寸为1
    在这里插入图片描述
    以上截至(https://www.runoob.com/w3cnote/the-friendship-algorithm-the-big-bang-theory.html)ide

/**
 * 堆排序算法:
 * @author Administrator
 * @time 2019年7月12日 下午9:08:02
 * 
 * 堆排序的前提:升序(构造大根堆),降序(构造小根堆)
 * 
 * 具体思路: https://blog.csdn.net/u010452388/article/details/81283998
 */


public class HeapSort {
	
	//数组数值交换
	public void swap(int[] arr,int i,int j) {
		int temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	}
	
	//构造大根堆
	public void bigRootHeap(int[] arr) {
		
		for(int i=0;i<arr.length;i++) {
			//设置当前索引节点
			int currentIndex = i;
			int fatherIndex = (currentIndex-1)/2;
			
			while(arr[currentIndex] > arr[fatherIndex]) {
				swap(arr,currentIndex,fatherIndex);
				
				currentIndex = fatherIndex;
				fatherIndex = (currentIndex-1)/2;
			}		
		}
	}
	
	//固定最大值,再构造大根堆
	public void heapNext(int[] arr,int index,int size) {
		int left = 2*index+1;
		int right = 2*index+2;
		while (left < size) {
            int largestIndex;
            //判断孩子中较大的值的索引
            if (arr[left] < arr[right] && right < size) {
                largestIndex = right;
            } else {
                largestIndex = left;
            }
            //比较父结点的值与孩子中较大的值,并肯定最大值的索引
            if (arr[index] > arr[largestIndex]) {
                largestIndex = index;
            }
            //若是父结点索引是最大值的索引,那已是大根堆了,则退出循环
            if (index == largestIndex) {
                break;
            }
            //父结点不是最大值,与孩子中较大的值交换
            swap(arr, largestIndex, index);
            //将索引指向孩子中较大的值的索引
            index = largestIndex;
            //从新计算交换以后的孩子的索引
            left = 2 * index + 1;
            right = 2 * index + 2;
        }

	}
	
	
	public void heapSort(int[] arr) {
		bigRootHeap(arr);
        int size = arr.length;
        while (size > 1) {
            //固定最大值
            swap(arr, 0, size - 1);
            size--;
            //构造大根堆
            heapNext(arr, 0, size);
 
        }

	}
	
	
	public static void main(String[] args) {
		
		int[] arr = new int[1000];
		
		for(int i=0;i<1000;i++) {
			if(i%2 == 0) {
				arr[i] = 2*i-i;
			}
			else {
				arr[i] = 2*i;
			}			
		}
		
		System.out.print("原数组:");
		for(int x:arr) {
			System.out.print(x+",");
		}
		
		HeapSort hs = new HeapSort();
		long start = System.nanoTime();
		hs.heapSort(arr);
		long end = System.nanoTime();
		System.out.println("\n堆排序消耗时间:"+(end-start));
		
		System.out.print("排序后数组:");
		for(int x:arr) {
			System.out.print(x+",");
		}
	}
}

在这里插入图片描述

快速排序算法:
快速排序是由东尼·霍尔所发展的一种排序算法。在平均情况下,排序 n 个项目要Ο(n log n)次比较。在最坏情况下则须要Ο(n2)次比较,但这种情况并不常见。事实上,快速排序一般明显比其余Ο(n log n) 算法更快,由于它的内部循环(inner loop)能够在大部分的架构上颇有效率地被实现出来。svg

快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。oop

算法步骤:ui

1 从数列中挑出一个元素,称为 “基准”(pivot),

2 从新排序数列,全部元素比基准值小的摆放在基准前面,全部元素比基准值大的摆在基准的后面(相同的数能够到任一边)。在这个分区退出以后,该基准就处于数列的中间位置。这个称为分区(partition)操做。

3 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,可是这个算法总会退出,由于在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。
在这里插入图片描述
(来自:https://www.runoob.com/w3cnote/the-friendship-algorithm-the-big-bang-theory.htm)

public class QuickSort {

	public static void quickSort(int[] arr,int left,int right) {
		//定义i,j而且将传递来的参数分别赋值给i,j
		int i = left;
		int j = right;
		
		//判断:当数组最左边的数的下标反而大于最右边的数的下标时,则参数传递存在错误
		if(i > j) {
			return;
		}
		//设置基准数
		int temp = arr[left];
		//判断:当数组下标左边不等于右边的时候,才能够进行查找与替换
		while(i != j) {
			/*
			 * 1.先在基准数右边进行查找比基准数小的数
			 * 2.找不到,便一直向数组的源头逐步向上找
			 * 3.找到时,便中止继续查找
			 */
			while(arr[j] >= temp && i < j) {
				j--;
			}
			/*
			 * 1.先在基准数左边边进行查找比基准数大的数
			 * 2.找不到,便一直向数组的末尾逐步向下找
			 * 3.找到时,便中止继续查找
			 */
			while(arr[i] <= temp && i < j) {
				i++;
			}
			
			/*
			 * 当知足最左下标小于最右下标时,将刚刚在数组右端比基准数小的数
			 * 与在数组中左端比基准数大的数,进行相互替换,以达到排序的做用
			 */
			if(i < j) {
				int tp = arr[j];
				arr[j] = arr[i];
				arr[i] = tp;
			}
			
		}
		/*
		 * 现将i=j时,i所对应的数组中的数的赋值在原基准数的位置
		 * (本例中默认是数组的第一个位置)
		 * 将基准数放置在刚才i=j的位置上
		 */
		arr[left] = arr[i];
		arr[i] = temp;
		
		//执行递归操做,分别对刚刚第一步排序的产生在基准书左边与右边的数组进行进一步的排序
		quickSort(arr,left,i-1);
		quickSort(arr,i+1,right);
	}

	public static void main(String[] args) {
		int[] arr = new int[1000];;
		
		/*系统本身产生一个足够大的数组
		 * 由于System.nanoTime()是以毫微秒为单位的时间计算
		 * 计算机运行速度很快,咱们须要产生一个足够大的数组来排序,
		 * 从而来观察不一样算法之间效率的差别
		 */
		for(int i=0;i<1000;i++) {
			if(i%2 == 0) {
				arr[i] = 2*i-i;
			}
			else {
				arr[i] = 2*i;
			}			
		}

		//遍历原数组
		System.out.print("原始数组:");
		for(int x:arr) {
			System.out.print(x+" ");
		}
		
		long start = System.nanoTime();
		quickSort(arr,0,arr.length-1);
		long end = System.nanoTime();
		
		//遍历排序后数组
		System.out.print("\n快速排序后:");
		for(int x : arr) {
			System.out.print(x+" ");
		}
		
		System.out.println("\n快速排序算法消耗时间:"+(end-start));
	}
}

在这里插入图片描述

堆排序是一种选择排序,复杂度通常认为就是O(nlogn)级。