排序算法
排序的定义
所谓排序,就是使一串记录,按照其中的某个或某个关键字的大小,递增或递减的排列起来的操作。排序算法,就是如何使得记录按照要求排列的方法。
排序算法的评价标准:
1、时间复杂度
2、空间复杂度
3、使用场景
4、稳定性
算法的分类
排序算法大致可以分为内部算法和外部算法。如果整个排序过程不需要借助于外部储存器(磁盘),所有的操作都在内存中完成,则称之为内部算法。如果参与排序树数据元素非常多,数据量非常大,则计算机必须借助外部储存器(如磁盘),这种排序称为外部排序。
1、冒泡排序(Buddle Sort)
定义
冒泡排序(Bubble Sort),是一种计算机科学领域的较简单的排序算法。
它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素列已经排序完成。
算法描述:
- 比较相邻的元素。如果第一个比第二个大,就交换它们两个;
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;
- 针对所有的元素重复以上的步骤,除了最后一个;
- 重复步骤1~3,直到排序完成。
Java实现
public static int[] Buddle_sort(int[] array){
if (array.length==0){
return array;
}
for (int i = 0; i < array.length-1; i++) {
for (int j = 0; j < array.length-1-i; j++) {
if (array[j]>array[j+1]){
int temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
}
}
}
return array;
}
public static void main(String[] args) {
int[] a = {2,44,38,5,47,36,26,27,4,19,50,48,5,3};
System.out.println(Arrays.toString(Buddle_sort(a)));
}
算法分析
最佳情况:T(n) = O(n) 最差情况:T(n) = O(n2) 平均情况:T(n) = O(n2)
2、选择排序(Selection Sort)
定义
选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理是:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。选择排序是不稳定的排序方法。
算法描述:
- 初始状态:无序区为R[1…n],有序区为空;
- 第i趟排序(i=1,2,3…n-1)开始时,当前有序区和无序区分别为R[1…i-1]和R(i…n)。该趟排序从当前无序区中-选出关键字最小的记录 R[k],将它与无序区的第1个记录R交换,使R[1…i]和R[i+1…n)分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区;
- n-1趟结束,数组有序化了。
java实现
//选择排序
public static int[] Selection_sort(int[] array){
int tag = 0;//记录下标
int temp =0;//交换中介
if (array.length==0){
return array;
}
for (int i = 0; i < array.length-1; i++) {
tag = i;
for (int j = i+1; j < array.length; j++) {
if (array[tag]>array[j]){
tag=j;//记录最小数的下标索引
}
}
//比较完成,进行交换
temp = array[tag];
array[tag] = array[i];
array[i] = temp;
}
return array;
}
算法分析
表现最稳定的排序算法之一,因为无论什么数据进去都是O(n2)的时间复杂度!
最佳情况:T(n) = O(n2) 最差情况:T(n) = O(n2) 平均情况:T(n) = O(n2)
3、插入排序(Insertion Sort)
定义
插入排序(Insertion-Sort)的算法描述是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。
算法描述:
- 从第一个元素开始,该元素可以认为已经被排序;
- 取出下一个元素,在已经排序的元素序列中从后向前扫描;
- 如果该元素(已排序)大于新元素,将该元素移到下一位置;
- 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
- 将新元素插入到该位置后;
- 重复步骤2~5。
java代码实现
//插入排序
public static int[] Insert_sort(int[] array){
if (array.length==0){
return array;
}
int preIndex =0;//前一个下标索引
int current=0;//要插入的数据
for (int i = 1; i < array.length; i++) {
current = array[i];
preIndex = i-1;
//查找数据的位置进行插入,对有序数组的数据进行逐个比较,找到位置之后结束循环
while (preIndex>=0 && array[preIndex]>current){
array[preIndex+1] = array[preIndex];
preIndex--;
}
//找到数据的插入位置preIndex+1
array[preIndex+1] = current;
}
return array;
}
算法的分析
插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。
最佳情况:T(n) = O(n) 最坏情况:T(n) = O(n2) 平均情况:T(n) = O(n2)
4、归并排序(Merge Sort)
定义
归并排序(Merge Sort)是建立在归并操作上的一种有效,稳定的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
、
算法描述:
- 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
- 设定两个指针,最初位置分别为两个已经排序序列的起始位置
- 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
- 重复步骤3直到某一指针超出序列尾
- 将另一序列剩下的所有元素直接复制到合并序列尾
简单描述
- 把长度为n的输入序列分成两个长度为n/2的子序列;
- 对这两个子序列分别采用归并排序;
- 将两个排序好的子序列合并成一个最终的排序序列
java代码实现
/*
* @paragm array[]
* @return
* */
//对当前的数组进行折半然后归并排序,使用的递归自下而上
public static int[] Merge_sort(int[] array){
if (array.length<2){return array;}
int middle = array.length/2;
int[] left = Arrays.copyOfRange(array, 0, middle);
int[] right = Arrays.copyOfRange(array, middle, array.length);
return merge(Merge_sort(left),Merge_sort(right));
}
//归并排序:将俩个排序好的数据合成一个排序数组
/*
* @param left
* @param right
* */
public static int[] merge(int[] left,int[] right){
//创建一个数据result用来存放合成的数组
int[] result = new int[left.length+ right.length];
int i =0;//result数组的下标
while (left.length>0 && right.length >0){
if (left[0] >= right[0]){
result[i++] = right[0];
right = Arrays.copyOfRange(right,1,right.length);
}
else {
result[i++] = left[0];
left = Arrays.copyOfRange(left,1,left.length);
}
}
//因为可能出现left或者right中的一方先完成数据的插入,所以我们要对剩下的另一方完成剩下的数据的插入
while (left.length>0){
result[i++] = left[0];
left = Arrays.copyOfRange(left,1,left.length);
}
while (right.length>0){
result[i++] = right[0];
right = Arrays.copyOfRange(right,1,right.length);
}
return result;
}
public static void main(String[] args) {
int[] a = {2,44,38,5,47,36,26,27,4,19,50,48,5,3};
System.out.println(Arrays.toString(Merge_sort(a)));
}
算法分析:
归并排序是一种稳定的排序方法。和选择排序一样,归并排序的性能不受输入数据的影响,但表现比选择排序好的多,因为始终都是O(nlogn)的时间复杂度。代价是需要额外的内存空间。
最佳情况:T(n) = O(n) 最差情况:T(n) = O(nlogn) 平均情况:T(n) = O(nlogn)
5、希尔排序(Shell Sort)
定义
希尔排序(Shell’s Sort)是插入排序的一种又称“缩小增量排序”(Diminishing Increment Sort),是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因 D.L.Shell 于 1959 年提出而得名。
算法描述:
- 选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;
- 按增量序列个数k,对序列进行k 趟排序;
- 每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
原始数组:颜色相同的为一组
初始增量为gap=length/2=5,整个数组被分为俩组,[7,6],[4,2].[9,8],[1,3],[5,10]
对5组分别进行直接插入排序,结果如下:
缩小增量gap=5/2=2,数组别分为俩组
再缩小增量gap=2/2=1,数组变为一组
最后再进行插入排序
java代码实现
public static int[] Shell_sort(int[] array){
int gap= array.length/2;//定义增量gap,这里我们以gap/2来缩小增量
int temp;//交换中介
while (gap>0) {
for (int i = gap; i < array.length; i++) {
temp = array[i];
int preIndex = i - gap;
while (preIndex >= 0 && array[preIndex] > array[i]) {
array[preIndex + gap] = array[preIndex];
preIndex -= gap;
}
array[preIndex + gap] = temp;
}
//进行完增量gap分组的排序后。对增量进行缩减
gap /= 2;
}
return array;
}
算法分析
希尔排序的核心在于间隔序列的设定。既可以提前设定好间隔序列,也可以动态的定义间隔序列。动态定义间隔序列的算法是《算法(第4版)》的合著者Robert Sedgewick提出的。
最佳情况:T(n) = O(nlog2 n) 最坏情况:T(n) = O(nlog2 n) 平均情况:T(n) =O(nlog2n)
6、快速排序(Quick Sort)
定义
快速排序由C. A. R. Hoare在1960年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
算法描述:
- 快速排序使用分治法来把一个串(list)分为两个子串(sub-lists)
- 从数列中挑出一个元素,称为 “基准”(pivot);
- 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
- 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
java代码实现
/*
* @param int[] array 要进行快速排序的数组
* @return
* */
public static void quick_sort(int[] array,int left,int right){
if (left<right){
int mid = get_mid(array,left,right);//中枢
quick_sort(array,left,mid-1);
quick_sort(array,mid+1, right);
}
}
private static int get_mid(int[] array, int left, int right) {
int pivot = array[left];//基准pivot
while (left<right){
while (array[right]>=pivot &&left<right) right--;
if (array[right]<pivot){ array[left] = array[right];}
while (array[left]<pivot && left<right) left++;
if (array[left]>pivot){ array[right] = array[left];}
}
array[left] = pivot;
return left;
}
算法分析:
最佳情况:T(n) = O(nlogn) 最差情况:T(n) = O(n2) 平均情况:T(n) = O(nlogn)
7、堆排序(Heap Sort)
定义
Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
算法描述:
- 将初始待排序关键字序列(R1,R2….Rn)构建成大顶堆,此堆为初始的无序区;
- 将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,……Rn-1)和新的有序区(Rn),且满足R[1,2…n-1]<=R[n];
- 由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。
8基数排序
9桶排序
10计数排序
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EMyTIKDe-1616729711995)(%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95.assets/image-20201224141901495.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fwMoU7N8-1616729711996)(%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95.assets/image-20201224144722675.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WFhRoPci-1616729711997)(%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95.assets/image-20201224144733301.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kDQlUsD1-1616729711998)(%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95.assets/image-20201224144750039.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2wpHZ1FZ-1616729711999)(%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95.assets/image-20201224144757208.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lHWChIx8-1616729712000)(%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95.assets/image-20201224144812328.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dpCtGDes-1616729712001)(%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95.assets/image-20201224144833397.png)]
;
- 由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。
8基数排序
9桶排序
10计数排序
[外链图片转存中…(img-EMyTIKDe-1616729711995)]
[外链图片转存中…(img-fwMoU7N8-1616729711996)]
[外链图片转存中…(img-WFhRoPci-1616729711997)]
[外链图片转存中…(img-kDQlUsD1-1616729711998)]
[外链图片转存中…(img-2wpHZ1FZ-1616729711999)]
[外链图片转存中…(img-lHWChIx8-1616729712000)]
[外链图片转存中…(img-dpCtGDes-1616729712001)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hwm1Pb5Q-1616729712003)(%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95.assets/image-20201224144841814.png)]