1、选择排序
选择排序(Selection sort)是一种简单直观的排序算法。其基本思想是:首先在未排序的数列中找到最小(or最大)元素,然后将其存放到数列的起始位置;接着,再从剩余未排序的元素中继续寻找最小(or最大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
样例:以数列{20,40,30,10,60,50}为例,演示其选择排序过程(如下图)。
排序流程如下:
第1趟:i=0。找出a[1]至a[5]中的最小值a[3]=10,然后将a[0]和a[3]互换。 数组变化:20,40,30,10,60,50 -- > 10,40,30,20,60,50
第2趟:i=1。找出a[2]至a[5]中的最小值a[3]=20,然后将a[1]和a[3]互换。 数组变化:10,40,30,20,60,50 -- > 10,20,30,40,60,50
第3趟:i=2。找出a[3]至a[5]中的最小值,由于该最小值大于a[2],该趟不做任何处理。
第4趟:i=3。找出a[4]至a[5]中的最小值,由于该最小值大于a[3],该趟不做任何处理。
第5趟:i=4。交换a[4]和a[5]的数据。 数组变化:10,20,30,40,60,50 -- > 10,20,30,40,50,60
程序:
package basic_package_01;
import java.util.Arrays;
//选择排序
public class Code_01_SelectionSort {
public static void selectionSort(int[] arr) {
if (arr == null || arr.length < 2) {
return; //排序的元素不为空且必须大于等于2个元素。
}
for(int i = 0; i < arr.length-1; i++) {
int minIndex = i;
// 寻找a[i+1]至序列末尾的最小值
for (int j = i + 1; j < arr.length; j++) {
minIndex = arr[j] < arr[minIndex] ? j : minIndex;
}
swap(arr, i, minIndex);
System.out.print("第"+ (i+1) +"躺:"+"找到的最小值下标是"+minIndex+", 本次排序结果为:");
printArray(arr);
}
}
private static void swap(int[] arr, int i, int j) {
// TODO Auto-generated method stub
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
// 打印数组
public static void printArray(int[] arr) {
if (arr == null) {
return;
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
public static void main(String[] args) {
int[] arr = {20,40,30,10,60,50};
System.out.print("待排序序列:");
printArray(arr); //打印原始数组
selectionSort(arr);
System.out.print("最终序列:");
printArray(arr);
}
}
程序结果:
时间复杂度和稳定性
选择排序的时间复杂度是 O(N²) :假设被排序的数列中有N个数。遍历一趟的时间复杂度是O(N),需要遍历多少次呢?N-1次,因此,选择排序的时间复杂度是 O(N²) 。
选择排序是稳定的算法,它满足稳定算法的定义:假设在数列中存在a[i]=a[j],若在排序之前,a[i]在a[j]前面;并且排序之后,a[i]仍然在a[j]前面。则这个排序算法是稳定的!
注:引用文章来源:通俗易懂讲解 选择排序 - 知乎
2、 插入排序
插入法排序原理
利用插入法对无序数组排序时,我们其实是将数组R划分成两个子区间R[1..i-1](已排好序的有序区)和R[i..n](当前未排序的部分,可称无序区)。插入排序的基本操作是将当前无序区的第1个记录R[i]插人到有序区R[1..i-1]中适当的位置上,使R[1..i]变为新的有序区。因为这种方法每次使有序区增加1个记录,通常称增量法。
插入排序与打扑克时整理手上的牌非常类似。摸来的第1张牌无须整理,此后每次从桌上的牌(无序区)中摸最上面的1张并插入左手的牌(有序区)中正确的位置上。为了找到这个正确的位置,须自左向右(或自右向左)将摸来的牌与左手中已有的牌逐一比较。
图解:根据其原理,我们把该无序数列看成两个部分,我们不难看出图中,首先我们把第一位3看成是有序数列,剩下的作为无序数列,因为要把后面的无序数列中的数插入到前面有序数列,所以依次把后面的数抽出,在前面找到合适位置插入。如图,先抽出44,与前面比较,比3大放在3后面,再抽出38,与前面比较,比44小,比3大,所以插入到3后面。依次类推,直到最后的一个数也插入到前面的有序数列中。
例:数组{9,3,1,4,2,7,8,6,5}。
————————————————
版权声明:本文为CSDN博主「萌中芢」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_42857603/article/details/81605124
代码:
package basic_package_01;
public class Code_01_InsertionSort {
public static void insertionSort(int[] arr) {
if(arr == null || arr.length < 2) {
return;
}
for (int i = 1; i < arr.length; i++) {
for(int j = i-1; j >= 0 && arr[j] > arr[j+1]; j--) {
swap(arr, j , j+1);
}
System.out.print("第" + i +"次,调换后排序结果:");
printArray(arr);
}
}
private static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
// 打印数组
public static void printArray(int[] arr) {
if (arr == null) {
return;
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
public static void main(String[] args) {
int[] arr = {9,3,1,4,2,7,8,6,5};
System.out.print("待排序序列:");
printArray(arr); //打印原始数组
insertionSort(arr);
System.out.print("最终序列:");
printArray(arr);
}
}
输出结果:
时间复杂度
在插入排序中,当待排序数组是有序时,是最优的情况,只需当前数跟前一个数比较一下就可以了,这时一共需要比较N- 1次,时间复杂度为O(N)。
最坏的情况是待排序数组是逆序的,此时需要比较次数最多,总次数记为:1+2+3+…+N-1,所以,插入排序最坏情况下的时间复杂度为O(N²) 。
平均来说,A[1..j-1]中的一半元素小于A[j],一半元素大于A[j]。插入排序在平均情况运行时间与最坏情况运行时间一样,是输入规模的二次函数。
空间复杂度
插入排序的空间复杂度为常数阶O(1)。