一、冒泡排序
(1)、基本思想
第一趟,从第0个记录到第n-1个记录,i和i+1关键码进行比较,与要求逆序则交换位置。一趟后最大的关键码就放到了n位置
第二趟,从第0个记录到第n-2进行第二趟冒泡。
如此重复n-1趟,如果在一趟中没有发生交换,说明数组已经是有序的了。
(2)、代码实现
//冒泡排序实现
public static void buble_sort(int[] arr){
//不合法检验
if(arr==null||arr.length<2){
return;
}
for(int i=0;i<arr.length-1;i++){
int flag=0;
for(int j=0;j<arr.length-i-1;j++){
if(arr[j]>arr[j+1]){
int tmp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=tmp;
flag=1;
}
}
if(flag==0) break;//一趟中如果没有交换说明已经排好序了
}
}
(3)、性能分析
冒泡排序的时间复杂度为O(n^2),空间复杂度为O(1),它是一种稳定的排序算法。
二、选择排序
(1)、基本思想
第i趟,从i+1到n-1 ,用一个变量保存最小值小标,最后变量位置和i位置进行交换
进行n-1趟
(2)、代码实现
//选择排序实现
public static void select_sort(int[] arr){
//不合法检验
if(arr==null||arr.length==0){
return;
}
for(int i=0;i<arr.length-1;i++){
int minIndex=i;
for(int j=i+1;j<arr.length;j++){
if(arr[minIndex]>arr[j]) minIndex=j;
}
if(minIndex!=i){
int tmp=arr[minIndex];
arr[minIndex]=arr[i];
arr[i]=tmp;
}
}
}
(3)、性能分析
选择排序交换次数较少,时间复杂度为O(n^2)。
举个例子,序列5 8 5 2 9, 我们知道第一遍选择第1个元素5会和2交换,那么原序列中2个5的相对前后顺序就被破坏了,所以选择排序是一个不稳定的排序算法
三、归并排序
(1)、基本思想
归并排序是基于一种被称为“分治”(divide and conquer)的策略。其基本思路是这样的:
1.对于两个有序的数组,要将其合并为一个有序数组,我们可以很容易地写出如下代码:
public void merge(int[] a, int[] b, int[] c){
int i=0,j=0,k=0;
while (i<=a.length && j<=b.length){
if (a[i]<=b[i]){
c[k++]=a[i++];
}
else{
c[k++]=b[j++];
}
}
while (i<=a.length){
c[k++]=a[i++];
}
while (j<=b.length){
c[k++]=b[j++];
}
}
容易看出,这样的合并算法是高效的,其时间复杂度可达到O(n)。
2.假如有一个无序数组需要排序,但它的两个完全划分的子数组A和B分别有序,借助上述代码,我们也可以很容易实现;
3.那么,如果A,B无序,怎么办呢?可以把它们再分成更小的数组。
4.如此一直划分到最小,每个子数组都只有一个元素,则可以视为有序数组。
5.从这些最小的数组开始,逆着上面的步骤合并回去,整个数组就排好了。
总而言之,归并排序就是使用递归,先分解数组为子数组,再合并数组。
(2)、代码实现
//归并排序实现
public static void MergeSort(int[] a, int[] b, int left, int right){
//当left==right的时,已经不需要再划分了
if (left<right){
int middle = (left+right)/2;
MergeSort(a, b, left, middle); //左子数组
MergeSort(a, b, middle+1, right); //右子数组
mergeSortedArray(a, b, left, middle, right); //合并两个子数组
}
}
// 合并两个有序子序列 arr[left, ..., middle] 和 arr[middle+1, ..., right]。temp是辅助数组。
public static void mergeSortedArray(int arr[], int temp[], int left, int middle, int right){
int i=left;
int j=middle+1;
int k=0;
while ( i<=middle && j<=right){
if (arr[i] <=arr[j]){
temp[k++] = arr[i++];
}
else{
temp[k++] = arr[j++];
}
}
while (i <=middle){
temp[k++] = arr[i++];
}
while ( j<=right){
temp[k++] = arr[j++];
}
//把数据复制回原数组
for (i=0; i<k; ++i){
arr[left+i] = temp[i];
}
}
(3)、性能分析
归并排序是稳定排序,它也是一种十分高效的排序。每次合并操作的平均时间复杂度为O(n),而完全二叉树的深度为|log2n|。总的平均时间复杂度为O(nlogn)。而且,归并排序的最好,最坏,平均时间复杂度均为O(nlogn)。
空间复杂度:需要一个辅助向量来暂存两有序子文件归并的结果,故其辅助空间复杂度为O(n)
java中Arrays.sort()采用了一种名为TimSort的排序算法,就是归并排序的优化版本。