一、冒泡排序
思想:n个数循环比较找出最大(或最小)的值,再重复比较在剩下的数中找到最大值
代码:
public static void BubbleSort(int[] numbers){
int temp;
int k=numbers.length;
boolean didSwap;
for(int i=0;i<k-1;i++){
didSwap=false; //当一轮都没交换说明已排好序
for(int j=0;j<k-i-1;j++){
if(numbers[j]>numbers[j+1]){
temp=numbers[j];
numbers[j]=numbers[j+1];
numbers[j+1]=temp;
didSwap=true;
}
}
if(didSwap==false)
return;
}
}
时间复杂度 最优 | O(n) 最坏| n(n-1)/2——>O(n2)
空间复杂度 O(1)
二、选择排序
思想:n个数循环比较找出最大(或最小)的值,再重复比较在剩下的数中找到最大值,比较的次数与冒泡一样,减少了交换的次数。
代码:
public static void SelectSort(int[] numbers){
for(int i=0,len=numbers.length-1;i<len;i++){
int min=numbers[0],min_id=0;
for(int j=i;j<numbers.length;j++){
if(min>numbers[j]){
min=numbers[j];
min_id=j;
}
}
numbers[min_id]=numbers[i];
numbers[i]=min;
}
}
时间复杂度 n(n-1)/2——>O(n2)
空间复杂度 O(1)
三、插入排序
思想:每次循环比较将一个数插入一个有序的序列中(一个即有序),从第二个数开始比较。
代码:
public static void InsertSort(int[] numbers){
for(int i=0;i<numbers.length;i++){
int currentNumber=numbers[i];
int j=i-1;
while(j>=0&&numbers[j]>currentNumber){ //中断条件时期优于冒泡,中断期望为length/2,所以比冒泡块1倍
numbers[j+1]=numbers[j];
j--;
}
numbers[j+1]=currentNumber;
}
}
时间复杂度 最优 | O(n) 最糟|n*(n-1)/2——>O(n2)
空间复杂度 O(1)
四、希尔排序
思想:根据插入算法每次自能移动一位的缺点,添加了个间隔值dk(=length/2),每轮比较将相隔dk的数据放在一组进行直接插入排序,在缩小dk重复循环,直至dk为1。
代码:
public static void ShellSort(int[] numbers){
int dk=numbers.length/2;
while(dk>=1){
ShellInsertSort(numbers,dk); //log2n
dk=dk/2;
}
}
public static void ShellInsertSort(int[] numbers,int dk){
for(int i=dk;i<numbers.length;i++){ //所有相隔dk的组合
if(numbers[i]<numbers[i-dk]){ //对每一种组合进行直接插入排序
int x=numbers[i];
int j=i-dk;
do{
numbers[j+dk]=numbers[j];
j=j-dk;
}
while(j>0&&numbers[j]>x);
numbers[j+dk]=x;
}
}
}
时间复杂度 O(nlog2n)
空间复杂度 O(n)
五、归并排序
思想:分治思想+将两个有序的序列合并。先将数组循环二分,直至一组数据只有一个,在开始向上合并。
代码:
public static void sort(int[] numbers){
sort(numbers,0,numbers.length);
}
public static void sort(int[] numbers,int pos,int end){
if(end-pos>1){
int mid=(end+pos)/2;
sort(numbers,pos,mid);
sort(numbers,mid,end);
MergeSort(numbers,pos,mid,end); //log2n次
}
}
public static void MergeSort(int[] numbers,int pos,int mid,int end){ int len1=mid-pos,len2=end-mid;
int[] array1=new int[len1]; ?
int[] array2=new int[len2]; ?
System.arraycopy(numbers, pos, array1, 0, len1);
System.arraycopy(numbers, mid, array2, 0, len2);
for(int i=pos,j=0,k=0;i<end;i++){
if(j==len1){
System.arraycopy(array2, k, numbers, i, len2-k);break;
}
if(k==len2){
System.arraycopy(array1, j, numbers, i, len1-j);break;
}
if(array1[j]<=array2[k]){
numbers[i]=array1[j++];
}
else{
numbers[i]=array2[k++];
}
}
}
时间复杂度 O(n*log2n)
空间复杂度 O(n)---->上面代码的空间复杂度为nlog2n,可以在递归之前申请n的数组
替代上面红色箭头所指的代码即可降低空间复杂度为O(n)
六、快速排序
思想:分治—>设置哨兵,将比哨兵大的数据分一边,小的分到一边,再递归重复。
代码:
public static void quickSort(int[] a,int left,int right){
if(left<right){
int key=a[left]; //哨兵
int low=left;
int high=right;
while(low<high){
while(low<high&&a[high]>key){
high--;
}
if(low<high)
a[low++]=a[high];
while(low<high&&a[low]<key){
low++;
}
if(low<high)
a[high--]=a[low];
}
a[low]=key;
quickSort(a,left,low-1);
quickSort(a,low+1,right);
}
}
时间复杂度 最优|O(nlog2n) 最糟|O(n2)
空间复杂度 最优|O(log2n) 最糟|O(n)
七、堆排序
思想:先将数据初始化为大堆顶(或小堆顶)的二叉树,然后每轮取出堆顶,再将最后一个支点赋给堆顶。大堆顶被破坏,在循环调整得到大堆顶,如此循环直至得到有序的序列。
代码:
public static void HeapSort(int[] numbers,int length){
BuildingHeap(numbers,length);
int len=numbers.length;
for(int i=len-1;i>=0;i--){
int temp=numbers[i];numbers[i]=numbers[0];numbers[0]=temp;
HeapAdjust(numbers,0,i);
}
}
public static void BuildingHeap(int[] numbers,int length){
for(int i=length/2;i>0;i--){
HeapAdjust(numbers,i-1,length);
}
}
public static void HeapAdjust(int[] numbers,int s,int length){
int tmp=numbers[s];
int child=2*s+1;
while(child<length){
if(child+1<length&&numbers[child]<numbers[child+1]){
++child;
}
if(numbers[s]<numbers[child]){
numbers[s]=numbers[child];
s=child;
child=2*s+1;
}else{
break;
}
numbers[s]=tmp;
}
}
时间复杂度 nlog2n
空间复杂度 o(1)
八、桶排序
思想:对于均匀分布的序列排序很好,将n个数据格局其值域分到m个组里,再讲各个组用其它排序对其排序。