1、直接选择排序
按升序排序,假设下标为0的数为最大值(max=0),用指针j从下标为0处开始遍历,找到比array[max]的值大的时候,max就为较大数的下标值,并把这个值与最后一个值交换,共有几个数,按此规律循环几次,循环过程中,无序数组的范围是:[0,array.length-i],有序数组为[array.length-i,array.length],代码如下:
`
for(int i=0;i<array.length;i++){
int max=0;
for(int j=0;j<array.length-i;j++){
if(array[j]>array[max]){
max=j;
}
}
int t=array[max];
array[max]=array[array.length-1-i];
array[array.length-1-i]=t;
}
`
2、堆排序(以建大堆为例)
大堆性质:父结点的值大于子节点的值
父结点下标若为i,那么他的左孩子结点下标为:2i+1;右孩子结点下标为:2i+2;
子节点下标若为j,那么他的父结点下标为:(j-1)/ 2;
先将一组数建成完全二叉树,然后利用向下调整的方式建成大顶堆,因为是大顶堆,所以下标为0的地方是无序部分的最大值,将无序部分的第一个数和最后一个数交换位置,此时无序部分的最后一个数就有序部分的第一个数,再将交换后的第一个数进行向下调成变成新的大顶堆,以此循环
建大堆向下调整:
public static void adjustdown(int[] array,int size,int index){
int max=2*index+1;
while (max<size){
while (max+1<size&&array[max+1]>array[max]){
max=max+1;
}
if(array[index]>array[max]){
break;
}
int t=array[max];
array[max]=array[index];
array[index]=t;
index=max;
max=2*index+1;
}
堆排序:
public static void heapSort(int[] array){
for(int i=(array.length-1-1)/2;i>=0;i--){
adjustdown(array,array.length,i);
}
for(int j=0;j<array.length;j++){
int t=array[0];
array[0]=array[array.length-j-1];
array[array.length-j-1]=t;
adjustdown(array,array.length-j-1,0);
}
}
3、冒泡排序
假设一组数: 8 6 2 1 4 3 5
第一次排序是从下标j=0处开始比较,若array[j]>array[j+1],则交换两个值,然后j++
经过一次排序后,这组数为: 6 2 1 4 3 5 8
以此循环,第二次排序后: 2 1 4 3 5 6 8
第三次排序后: 1 2 3 4 5 6 8
public static void bubleSort(int[] array){
for(int i=0;i<array.length;i++){
for(int j=0;j<array.length-i-1;j++){
if(array[j]>array[j+1]){
int t=array[j];
array[j]=array[j+1];
array[j+1]=t;
}
}
}
}
4、插入排序
从第一个元素开始,该元素可以认为已经被排序,
取出下一个元素,在已经排序的元素序列中从后向前扫描,
如果该元素(已排序)大于新元素,将该元素移到下一位置,
重复步骤3,直到找到已排序的元素小于或者等于新元素的位置,
将新元素插入到该位置后,
重复步骤2~5
public static void inSort(int[] array){
for(int i=0;i<array.length;i++){
int key=array[i];
int j=i-1;
for(;j>=0&&array[j]>key;j--){
array[j+1]=array[j];
}
array[j+1]=key;
}
}
5、希尔排序
希尔排序是直接插入排序的升级版,他将一组数分成了gap个数为一组的,每组之间对应下标相同的数进行比较,一趟完了之后,再将数分成(gap/2)个数,再将每组对应下标相同的数进行比较,以此循环,直到gap=1后,排序 完成,第一次gap=array.length/2;
下图大概演示排序过程:
代码如下:
public static void inSortwithgap(int[] array,int gap){
for(int i=0;i<array.length;i++){
int key=array[i];
int j=i-gap;
for(;j>=0&&array[j]>key;j=j-gap){
array[j+gap]=array[j];
}
array[j+gap]=key;
}
}
public static void shellSort(int[] array){
int gap=array.length;
while (true){
gap=gap/2;
inSortwithgap(array,gap);
if(gap==1){
break;
}
}
}
6、快速排序
快速排序就是找到一个基准值,基准值左边的数都比这个基准值小,右边都比基准值大,然后在将基准值左边和右边分别单独看成两个数组,再找出各自的基准值,遵循左边比基准值小,右边比基准值大的方式不断进行递归
快速排序代码如下:
public static void quickSortInner(int[] array,int left,int right){
if(left>=right){
return;
}
int p=parition(array,left,right);
quickSortInner(array,left,p-1);
quickSortInner(array,p+1,right);
}
public static void quickSort(int[] array){
quickSortInner(array,0,array.length-1);
}
找基准值并排序方式
1、hover法
定义基准值为数组最后一个数,一个从下标为0处开始,定义为begin指针,另一个从array.length-1处开始,定义为end指针,begin的左边都要小于等于基准值,end的右边都要大于等于基准值,若begin遍历数组过程中碰到比基准值大的,则停下,让end指针开始遍历,若end指针碰到比基准值小的,也停下,此时交换begin和end的两个数,以此循环,当不满足begin<end这个条件时,交换begin所指元素和基准值
代码如下:
public static int parition(int[] array, int left, int right){
int begin=left;
int end=right;
int p =array[right];
while (begin<end){
while (begin<end&&array[begin]<=p){
begin++;
}
while (begin<end&&array[end]>=p){
end--;
}
int t=array[begin];
array[begin]=array[end];
array[end]=t;
}
int e=array[begin];
array[begin]=array[right];
array[right]=e;
return begin;
}
2、挖坑法
挖坑法 与hover法相差不大,差别就在于,使用挖坑法时,当begin指针碰到比基准值大的数时,不是停下,而是将begin指针的值赋给end指针,在让end指针开始遍历,此时begin指针的位置是空的,当end指针碰到比基准值小的时候,将end指针的值赋给空着的begin指针,在让begin指针开始继续遍历,以此循环,最后begin和end指针相遇时,这个指针指向位置应该是空的,将基准值赋给begin指针(此时begin==end),这样就完成了基准值左边比基准值小,右边比基准值大的顺序
代码如下:
public static int parition(int[] array,int left,int right){
int begin=left;
int end=right;
int p=array[right];
while (begin<end){
while (begin<end&&array[begin]<=p){
begin++;
}
array[end]=array[begin];
while (begin<end&&array[end]>=p){
end--;
}
array[begin]=array[end];
}
array[begin]=p;
return begin;
}
3、前后下标法
创建两个指针,一个指针找大于基准值的值,另一个指针找小于基准值的值
两个指针 分别为i和d;i和d都从left开始,基准值为最右边的数,让i开始遍历数组,遇到比基准值大的数就跳过(i++),遇到比基准值小的数就停下,如果array[i]和array[d]不相等的话就交换这两个值,然后让d++,直到i遍历完整个数组,最后将d指针指向的元素和最后一个元素交换,就完成了基准值左边比基准值小,右边比基准值大的顺序
public static int parition3(int[] array,int left,int right){
int d=left;
for(int i=left;i<right;i++){
if(array[i]<array[right]){
swap(array,d,i);
d++;
}
}
swap(array,d,right);
return d;
}
7、归并排序
1、把要排序区间平均切分为两部分
2、分治算法,对左右两个区间进行同样方式的排序
直到 size1 已经有序
size0 区间没有数了
3、合并左右两个两个有序区间到一个有序区间(需要额外空间)
public static void merge(int[] array,int low,int mid,int high){
int[] extra = new int[high-low];
int i=low;//遍历array[low,mid)
int j=mid;//遍历array[mid,high)
int x=0;//遍历extra
while(i<mid&&j<high){
if(array[i]<array[j]){
extra[x++]=array[i++];
}else {
extra[x++]=array[j++];
}
}
while (i<mid){
extra[x++]=array[i++];
}
while (j<high){
extra[x++]=array[j++];
}
for(int k=low;k<high;k++){
array[k]=extra[k-low];
}
}
public static void mergeSortInner(int[] array,int low,int high){
if(low>=high){
return;
}
if(low==high-1){
return;
}
//需要排序的区间array[low,high)
//1、平均切分
int mid=low+(high-low)/2;
//2、分治两个小区间
mergeSortInner(array,low,mid);
mergeSortInner(array,mid,high);
//左右两个小区间已经有序了
merge(array,low,mid,high);
}
public static void mergeSort(int[] array){
mergeSortInner(array,0,array.length);
}