首先排序分为四种:
交换排序: 包括冒泡排序,快速排序。
选择排序: 包括直接选择排序,堆排序。
插入排序: 包括直接插入排序,希尔排序。
归并排序: 归并排序。
(一) 冒泡排序
冒泡排序的基本思想是,对相邻的元素进行两两比较,顺序相反则进行交换,这样,每一趟会将最小或最大的元素“浮”到顶端,最终达到完全有序。时间复杂度为==O(n^2)==。
/**
* 冒泡排序
*
* @param arr
*/
public static void bubbleSort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
boolean flag = true;//设定一个标记,若为true,则表示此次循环没有进行交换,也就是待排序列已经有序,排序已然完成。
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
swap(arr,j,j+1);
flag = false;
}
}
if (flag) {
break;
}
}
}
(二)插入排序
想想扑克牌就很好理解了。时间复杂度为==O(n^2)==
Java代码实现
public static void insertSort(int[] A){
for(int right = 1;right < A.length;right++){
int temp = A[right];
int left = right-1;
while(left >= 0 && A[left]>temp){
A[left+1] = A[left];
left--;
}
A[left+1] = temp;
}
}
复杂度分析
①插入排序的时间复杂度 就是判断比较次数有多少,而比较次数与 待排数组的初始顺序有关,当待排数组有序时,没有移动操作(第8行for不成立),此时复杂度为O(N),当待排数组是逆序时,比较次数达到最大–对于下标 i 处的元素,需要比较 i-1 次。总的比较次数:1+2+…+N-1 ,故时间复杂度为==O(n^2)==
①可以看出,算法中只用到了一个临时变量(第6行),故空间复杂度为O(1)
(三)归并排序
思想
分解:分解待排序的n个元素的序列成n/2个元素的两个子序列
解决:使用归并排序递归地排序两个子序列
合并:合并两个已经排序好地子序列为一个序列 产生答案
public static int[] mergeSort(int[] A ,int left,int right){
if(left < right){
int mid = left + (right - left)/2;
//分
mergeSort(A,left,mid);
mergeSort(A,mid+1,right);
//合并
mergeGetArray(A,left,mid,right);
}
return A;
}
public static void mergeGetArray(int[] A,int left,int mid,int right){
int[] TempRes = new int[right-left+1];
int i = left,j = mid +1;
int k = 0;
while(i <= mid && j <= right){
if(A[i]<A[j]){
TempRes[k++] = A[i++];
}else{
TempRes[k++] = A[j++];
}
}
while(i <= mid){
TempRes[k++] = A[i++];
}
while(j <= right){
TempRes[k++] = A[j++];
}
for(i = 0;i < TempRes.length;i++){
A[left+i] = TempRes[i];
}
}
(四)堆排序
堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为==O(nlogn)==,它也是不稳定排序。
思想:
将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了
代码实现
维护堆的性质的函数
//维护堆的性质的函数,根据大小来调整某个结点以及它的孩子结点的位置
MAX_HEAPIFY(A,i){
left = 2i+1; //左孩子
right = 2i+2 ; //右孩子
//以下为判断结点以及它的孩子结点哪个最大,孩子结点比父节点大则调整二者位置
if( A[left] <= A.heap-size and A[Left]>A[i])
largest = Left;
else largest = i;
if( A[right] <= A.heap-size and A[right]>A[largest])
largest = r;
if( largets != i)
{
exchage A[i] with A[largest]
MAX_HEAPIFY(A,largest)
}
}
构建堆的函数
//构建堆的函数
BUID-HEAP(A){
A.heap-size = A.length;
for(int i = A.length/2-1;i>=0;i++){
MAX-HEAPIFY(A,i);//从最后一个非叶子结点开始调整,直到根节点的index为0
}
}
有了前面的铺垫,我们可以很容易写出堆排序
堆排序:
HEAP-SORT(A){
BUID-HEAP(A) //构建堆
for(int i = A.length-1;A>=0;A--){
exchange A[0] with A[i] //每次将堆的顶端也就是最大值放在数组最后边
A.heap-size = A.heap-size -1
MAX-HEAPIFY(A,1) //维护堆
}
}
```
### (五)快速排序
在平均状况下,排序 n 个项目要==Ο(n log n)== 次比较。在最坏状况下则需要Ο(n^2)次比较,但这种状况并不常见。
快速排序使用分治法(Divide and conquer)策略(归并排序也是分治法)来把一个串行(list)分为两个子串行(sub-lists)。是冒泡排序的改进型.
**算法步骤:**
1. 首先在数组中选择一个基准点(该基准点的选取可能影响快速排序的效率,后面讲解选取的方法)
2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
``` java
public static void QuickSort(int[] arr,int low,int high){
while(low < high){
int mid = Division(arr,low,high);
QuickSort(arr,low,mid-1);
QuickSort(arr,mid+1,high);
}
}
private static int Division(int[] arr,int low,int high) {
//选择一个基准数,一次循环将其放到属于它的位置
int temp = arr[low];
while(low < high){
while(low < high && arr[high] >= temp){
high--;
}
arr[low] = arr[high];
while(low < high && arr[low] <= temp){
low++;
}
arr[high] = arr[low];
}
arr[low] = temp;
return low;
}
<div class="se-preview-section-delimiter"></div>
注意:快速排序在序列中元素很少时,效率将比较低,不然插入排序,因此一般在序列中元素很少时使用插入排序,这样可以提高整体效率。
(六)直接选择排序
直接选择排序最类似于人的本能思想,比如把大小不一的玩具让三岁小毛孩对大小排个序,那小孩首先会在这么多玩具中找到最小的放在第一位,然后找到次小的放在第二位,以此类推。。。。。。
public static void SelectSort(int[] arr){
for(int i = 0;i<arr.length-1;i++){
int Index = i;
for(int j = i+1;j<arr.length;j++){
if(arr[Index]>arr[j])
Index = j;
}
//swap arr[i] with arr[Index]
int temp = arr[i];
arr[i] = arr[Index];
arr[Index] = temp;
}
}
<div class="se-preview-section-delimiter"></div>
(七)希尔排序
希尔是插入排序的改进版。 如果当数据是”5, 4, 3, 2, 1“的时候,此时我们将“无序块”中的记录插入到“有序块”时,估计俺们要崩盘,
shell根据这个弱点进行了算法改进,融入了一种叫做“==缩小增量排序法==”的思想。
首先要明确一下增量的取法:
第一次增量的取法为: d=count/2;
第二次增量的取法为: d=(count/2)/2;
最后一直到: d=1;
public static void shellSort(int[] arr){
int j = 0;
int temp = 0;
for(int incre = arr.length/2 ; incre>0 ;incre /= 2){
for(int i = incre; i < arr.length;i++){
temp = arr[i];
for(j = i-incre; j >= 0 ; j -= incre){
if(temp < arr[j]){
arr[j + incre] = arr[j];
}else{
break;
}
}
arr[j + incre] = temp;
}
}
}