排序算法分为内部排序和外部排序,其中内部排序中的8大排序算法,稳定的算法有:直接插入排序算法、冒泡算法、归并排序、基数排序;不稳定的算法有:希尔排序(增量的选择不确定)、简单选择排序、快速排序、堆排序。
排序的稳定性为如果排序链表中有相等的两个数,排序前后这两个数的相对位置是否发生了变化,如果发生变化,则为不稳定排序,反之即为稳定排序;例如5 3 3 4 3 8 9 10 11,快排时第一趟5与3交换,打破了3的相对位置,故为不稳定排序。
(1)直接插入排序
直接插入排序是在一个有序的序列中依次插入一个元素使之继续为有序的序列,直至最后一个元素完成;时间复杂度为o(n^2)。例如:序列5 3 3 4 3 8 9 10 11
[5] 3 3 4 3 8 9 10 11
[3 5] 3 4 3 8 9 10 11
[3 3 5] 4 3 8 9 10 11
[3 3 4 5] 3 8 9 10 11
[3 3 3 4 5] 8 9 10 11
…………..
[3 3 3 4 5 8 9 10 11]
代码为:
public static void main(String[] arg) {
int[] a = {12,20,5,16,15,1,30,45,23,9};
InsertionSort(a);
System.out.print(Arrays.toString(a));
}
public static void InsertionSort(int[] a) {
if(a==null||a.length==0||a.length==1) {
return ;
}
for(int i=1;i<a.length;i++) {
for(int j=0;j<i;j++) {
if(a[i]<a[j]) {
int temp=a[j];
a[j]=a[i];
a[i]=temp;
}
}
}
}
(2)希尔排序
希尔排序为改进后的直接插入排序,先取一个增量,在增量组成的序列中进行直接插入排序;时间复杂度为o(n^1.3)属于o(nlogn)~o(n^2),平均复杂度为o(n);序列12,20,5,16,15,1,30,45,23,9:先取增量为10/2位5
增量为5:1 20 5 16 9 12 30 45 23 15
增量为2:1 16 5 12 9 15 23 20 30 45
增量为1:1 5 9 12 15 16 20 23 30 45
代码为:
public static void main(String[] arg) {
int[] a = {12,20,5,16,15,1,30,45,23,9};
shellSort(a);
System.out.print(Arrays.toString(a));
}
public static void shellSort(int[] a) {
if(a==null||a.length==0||a.length==1) {
return ;
}
int increase=a.length/2;
while(increase>0) {
for(int i=0;i<a.length;i++) {
for(int j=i;j<a.length-increase;j+=increase) {
if(a[j]>a[j+increase]) {
int temp=a[j];
a[j]=a[j+increase];
a[j+increase]=temp;
}
}
}
increase=increase/2;
}
}
(3)简单选择排序
简单选择排序为从一个数组中第一选择一个最小的置为第一个排序元素,第二次在剩余的数中再选择一个最小的为第二个排序元素,依次类推,知道最后一个元素。时间复杂度为o(n^2)。例如:序列5 3 3 4 3 8 9 10 11
[3] 5 3 4 3 8 9 10 11
[3 3] 5 4 3 8 9 10 11
[3 3 3 ]5 4 8 9 10 11
[ 3 3 3 4]5 8 9 10 11
………
[3 3 3 4 5 8 9 10 11]
代码为:
public static void main(String[] arg) {
int[] a = {12,20,5,16,15,1,30,45,23,9};
choseSort(a);
System.out.print(Arrays.toString(a));
}
public static void choseSort(int[] a){
if(a==null||a.length==0||a.length==1){
return ;
}
for(int i=0;i<a.length;i++){
int min=i;
for(int j=i;j<a.length;j++){
if(a[min]>a[j]){
int temp=a[j];
a[j]=a[min];
[min]=temp;
}
}
}
}
(4)冒泡排序
冒泡排序为相邻的两个数比较,然后交换位置使得较大的往下沉,较小的往上冒;时间复杂度为o(n^2)。例如:序列5 3 2 4 3 1 8
第一趟排序后:3 2 4 1 5 8
第二趟排序后:2 3 1 4 5 8
第三趟排序后:2 1 3 4 5 8
第四趟排序后:1 2 3 4 5 8
……..
代码为:
public static void main(String[] arg) {
int[] a = {12,20,5,16,15,1,30,45,23,9};
choseSort(a);
System.out.print(Arrays.toString(a));
}
public static void choseSort(int[] a) {
if(a==null||a.length==0||a.length==1) {
return ;
}
for(int i=0;i<a.length-1;i++) {
for(int j=0;j<a.length-1-i;j++) {
if(a[j]>a[j+1]) {
int temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}
}
}
(5)快速排序
快速排序为先找一个基准点,每趟排序完后基准点之前的都比基准点小,基准点之后的都比基准的大,首个基准点一般为序列的第一个元素,然后递归基准点前后的两个序列。快速排序的时间复杂度为o(nlogn)。例如:12 20 5 16 15 1 30 45 23 9
第一趟排序过程为:基准点位12,12与9相比
9 20 5 16 15 1 30 45 23 12
20与12相比
9 12 5 16 15 1 30 45 23 20
23与12相比,45与12相比,30与12相比顺便不变,1与12相比
第一趟排序完成后:[9 1 5 16 15] 12 [30 45 23 20]
依次类推。。。。
代码为:
public static void main(String[] arg) {
int a[] = { 51, 46, 20, 18, 65, 97, 82, 30, 77, 50 };
quickSort(a,0,a.length - 1);
System.out.print(Arrays.toString(a));
}
private static void quickSort(int[] a, int start, int end) {
if (start < end) {
int middle = getMiddle(a, start, end); //将list数组进行一分为二
quickSort(a, start, middle - 1); //对低字表进行递归排序
quickSort(a, middle + 1, end); //对高字表进行递归排序
}
}
private static int getMiddle(int[] a, int start, int end) {
int temp=a[start];
while(start<end) {
while(start<end&& a[end]>=temp) {
end--;
}
a[start]=a[end];//把小的网低端放
while(start<end&& a[start]<=temp) {
start++;
}
a[end]=a[start];//把大的网高端放
}
a[start]=temp;//现在a[start]为中轴
return start;
}
(6)堆排序
堆排序为将一个序列构建成大顶堆(小顶堆),将堆顶的元素与堆中最后的元素交换,并且踢出堆顶元素,然后依次再在剩余的数中建立新的大顶堆,直到最后只有两个元素时,踢出大的元素,排序结束;堆排序的时间复杂度为o(nlogn)。
(7)归并排序
归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。归并排序的时间复杂度为o(nlogn)。
(8)基数排序
将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。