排序算法(一):插入排序与堆排序
2017-04-24 04:11
211 查看
排序算法是算法研究中最基础的问题,本文针对排序算法,介绍几种排序算法的基本方法、时间复杂度及Java实现等内容。
原址性 :如果输入数组中仅有常数个元素需要在排序的过程中存储在数组之外,那么排序算法就是原址的。
常用排序算法的运行时间比较
上表中,n表示要排序数据项数量。对于计数排序,数据项均在集合{0,1,...,k}内。对于基数排序,每个数据项都是d位数字的整数,每位数字可能取k个值。对于桶排序,假定关键字是半开区间[0,1)内服从均匀分布的n个实数。
示例代码
生成一个随机数组并进行插入排序,运行结果如下:
运行结果
最大堆 : 二叉堆又可以分为两种形式:最大堆和最小堆。最大堆的父节点的数据要比子节点的都大,最小堆则是都要小。堆排序算法中用的是最大堆,构造优先队列一般用最小堆。
堆的高度 : 一个堆节点的高度就是某节点到叶节点最长的简单路径的边数。而堆的高度则对应根节点的高度。就是O(lgn).
通过该示例,我们可以看出,对左右子树都是最大堆的根节点维护最大堆的方法。
所以将一个普通的堆维护成最大堆的方法,就是从底到根依次维护一次。不过不难发现,最底层的节点是没有子节点的,自然满足最大堆。也就是应该从开始有子节点的节点处开始倒序遍历维护节点。根据完全二叉树的性质,这个节点就是 heap.size / 2.
实现代码
运行结果
原址性 :如果输入数组中仅有常数个元素需要在排序的过程中存储在数组之外,那么排序算法就是原址的。
常用排序算法的运行时间比较
上表中,n表示要排序数据项数量。对于计数排序,数据项均在集合{0,1,...,k}内。对于基数排序,每个数据项都是d位数字的整数,每位数字可能取k个值。对于桶排序,假定关键字是半开区间[0,1)内服从均匀分布的n个实数。
一、插入排序
插入排序的思想就类似于我们玩牌,拿到手的是一把乱牌。我们从左到右排序。从第二张开始,我们与第一张比较,小的话就插到第一张前面。到后面某一张牌,我们会依次和前面的牌进行比较,直到比该牌小的位置,放到它的后面。示例代码
public static void sortInsert(int[] n){ //int count = 0; for(int i = 1; i < n.length; i++) { int key = n[i]; int j = i - 1; while(j >= 0 && n[j] > key){ n[j+1] = n[j]; j--; } n[j+1] = key; System.out.print(i + ":"); for(int num: n) System.out.print(num + " "); System.out.println(); } }
生成一个随机数组并进行插入排序,运行结果如下:
运行结果
E:\code\jv\alg0rithmOjava\排序>java InsertSort 35 58 24 75 77 17 73 64 66 88 1:35 58 24 75 77 17 73 64 66 88 2:24 35 58 75 77 17 73 64 66 88 3:24 35 58 75 77 17 73 64 66 88 4:24 35 58 75 77 17 73 64 66 88 5:17 24 35 58 75 77 73 64 66 88 6:17 24 35 58 73 75 77 64 66 88 7:17 24 35 58 64 73 75 77 66 88 8:17 24 35 58 64 66 73 75 77 88 9:17 24 35 58 64 66 73 75 77 88 17 24 35 58 64 66 73 75 77 88
二、堆排序
堆排序通过“堆”数据结构进行排序,其时间复杂度是O(nlgn),并具有空间原址性。结合了插入排序和归并排序的优点。1. 堆
(二叉)堆是一个数组,可以近似的看成一个完全二叉树,树上的每一个节点对应数组中的一个元素。堆heap的数组Array包括两个属性,一个是数组的长度A.length,一个是堆的大小heap.size,并有 0 <= heap.size <= A.length。也就是说,数组中的数据不一定都是堆的有效数据。最大堆 : 二叉堆又可以分为两种形式:最大堆和最小堆。最大堆的父节点的数据要比子节点的都大,最小堆则是都要小。堆排序算法中用的是最大堆,构造优先队列一般用最小堆。
堆的高度 : 一个堆节点的高度就是某节点到叶节点最长的简单路径的边数。而堆的高度则对应根节点的高度。就是O(lgn).
2. 建堆
通过该示例,我们可以看出,对左右子树都是最大堆的根节点维护最大堆的方法。
所以将一个普通的堆维护成最大堆的方法,就是从底到根依次维护一次。不过不难发现,最底层的节点是没有子节点的,自然满足最大堆。也就是应该从开始有子节点的节点处开始倒序遍历维护节点。根据完全二叉树的性质,这个节点就是 heap.size / 2.
实现代码
public void builtMaxHeapify(){ for(int i = heapSize/2; i >= 0; i--) { MaxHeapify(i); } } public void exchange(int i, int j) { heapArray[i] = heapArray[i] + heapArray[j]; heapArray[j] = heapArray[i] - heapArray[j]; heapArray[i] = heapArray[i] - heapArray[j]; } public void MaxHeapify(int i) { int largest = i; int l = (i + 1) << 1; int r = l + 1; if( l <= heapSize && heapArray[l-1] > heapArray[i]) largest = l-1; else largest = i; if( r <= heapSize && heapArray[r -1] > heapArray[largest]) largest = r-1; if(largest != i){ heapArray[i] = heapArray[i] + heapArray[largest]; heapArray[largest] = heapArray[i] - heapArray[largest]; heapArray[i] = heapArray[i] - heapArray[largest]; MaxHeapify(largest); } } }
运行结果
>java Test 18 26 66 75 1 53 47 80 47 71 80 75 66 47 71 53 47 26 18 1 1 75 66 47 71 53 47 26 18 80 75 71 66 47 1 53 47 26 18 18 71 66 47 1 53 47 26 75 71 47 66 26 1 53 47 18 18 47 66 26 1 53 47 71 66 47 53 26 1 18 47 47 47 53 26 1 18 66 53 47 47 26 1 18 18 47 47 26 1 53 47 26 47 18 1 1 26 47 18 47 47 26 1 18 18 26 1 47 26 18 1 1 18 26 18 1 1 18 1 1 18 26 47 47 53 66 71 75 80
相关文章推荐
- 数据结构与算法:七种排序算法总结(冒泡排序、选择排序、直接插入排序、希尔排序、堆排序、归并排序、快速排序)
- 常用的排序算法:冒泡,简单选择,直接插入,快速排序,堆排序
- python排序算法-冒泡排序,选择排序,直接插入排序,希尔排序,归并排序,快速排序,堆排序
- 数据结构6-排序算法(直接插入排序、希尔排序、快速排序、归并排序和堆排序)
- 6种排序算法及其比较 简单选择排序,堆排序,简单插入排序,希尔排序,冒泡排序,快速排序,归并排序
- 排序算法: 冒泡排序, 快速排序,希尔排序,直接插入排序 ,直接选择排序,归并排序,堆排序
- 排序算法(堆排序,归并排序,快速排序、选择排序、直接插入排序)
- 排序算法java版,速度排行:冒泡排序、简单选择排序、直接插入排序、折半插入排序、希尔排序、堆排序、归并排序、快速排序
- 【Java】八个常用的排序算法:插入排序、冒泡排序、选择排序、希尔排序 、快速排序、归并排序、堆排序和LST基数排序
- 排序算法(1):插入排序,选择排序,希尔排序,堆排序
- 排序算法java版,速度排行:冒泡排序、简单选择排序、直接插入排序、折半插入排序、希尔排序、堆排序、归并排序、快速排序
- 排序算法复习:直接插入排序、堆排序、快排、冒泡排序
- C语言实现基本排序算法----排序(直接插入排序,SHELL排序,冒泡排序,快速排序,简单选择排序,堆排序)
- 排序算法(堆排序,直接插入排序,折半插入排序,希尔排序)
- 排序算法汇总(选择排序 ,直接插入排序,冒泡排序,希尔排序,快速排序,堆排序)
- 排序算法复习(Java实现):插入,冒泡,选择,Shell,快速排序, 归并排序,堆排序,桶式排序,基数排序
- 排序算法复习(Java实现)(一): 插入,冒泡,选择,Shell,快速排序
- 排序算法系列——直接插入排序
- 排序算法001——直接插入排序
- 排序算法2--简单选择排序、堆排序