用到的工具:print、swap
/**print工具方法*/
private static void print(int[] a) {
for(int i=0;i<a.length;i++){
System.out.print(a[i]+" ");
}
System.out.println();
}
/**swap工具方法*/
private static void swap(int[] a, int i, int j) {
int temp;
temp=a[i];
a[i]=a[j];
a[j]=temp;
}
(一) 冒泡排序
算法描述:
(1). 设待排序记录序列中的记录个数为n。
(2). 一般地,第i趟起泡排序从0到n-i-1。
(3). 依次比较相邻两个记录的关键字,如果发生逆序,则交换之。
(4). 其结果是这n-i-1个记录中,关键字最大的记录被交换到第n-i-1的位置上,最多作n-1趟。
代码演示:
/**冒泡排序方法:*/
public static int[] BubbleSortMethod(int[] a){
for(int i=0;i<a.length;i++){
/**1.相邻的两个(a[j]、a[j+1])相互比较,j是从0到a.length-i-1*/
for(int j=0;j<a.length-i-1;j++){
if(a[j]>a[j+1]){
swap(a, j, j+1);
}
}
}
return a;
}
(二)近似选择排序
代码描述:
(1).设待排序记录序列中的记录个数为n。
(2).一般地,第i趟起泡排序从 i+1到n。
(3).依次用第i个与[i+1,n]之间的数比较,将得到的最大的值放在n-1的位置,依次类推,直到i为n-1。
代码演示:
public static void ApproximateSelectionSort(int[] a){
for(int i=0;i<a.length;i++){
/**第i个与[i+1,a.length]之间的所有进行比较,得到一个最大的放到n-i的位置上。*/
for(int j=i+1;j<a.length;j++){
if(a[i]>a[j]){
swap(a, i, j);
}
}
}
print(a);
}
(三)选择排序
算法描述
(1)首先通过n-1次比较,从n个数中找出最小的。
(2) 将它与第一个数交换——第一趟选择排序,结果最小的数被安置在第一个元素位置上。
(3)再通过n-2次比较,从剩余的n-1个数中找出关键字次小的记录,将它与第二个数交换——第二趟选择排序。
(4)重复上述过程,共经过n-1趟排序后,排序结束。
代码演示:
public static void selectSort(int[] a){
for(int i=0;i<a.length;i++){
int temp=a[i];//取第i个数为最小值
int k=i;//最小值的位置k为i
for(int j=i;j<a.length;j++){
if(temp>a[j]){//如果第j个数比最小值还要小,进行交换
temp=a[j];
k=j;
}
}
swap(a,i,k);
}
print(a);
}
(四)直接插入排序
算法描述:
记录存放在数组R[0….n-1]中,排序过程的某一中间时刻,R被划分成两个子区间R[0…i-1]和R[i….n-1],其中:前一个子区间是已排好序的有序区;后一个子区间则是当前未排序的部分。
基本操作:
将当前无序区的第1个记录R[i]插入到有序区R[0….i-1]中适当的位置,使R[0…i]变为新的有序区。
操作细节:
当插入第i(i≥1)个对象时, 前面的r[0], r[1], …, r[i-1]已经排好序。
用r[i]的关键字与r[i-1], r[i-2], …的关键字顺序进行比较(和顺序查找类似),如果小于,则将r[x]向后移动(插入位置后的记录向后顺移);找到插入位置即将r[i]插入。
代码演示:
public static void Straight_Insertion_Sort(int[] a){
for(int i=0;i<a.length-1;i++){
int temp=a[i+1];//临时需要插入的值
while(temp<a[i]){//循环条件:当需要插入的值比其前边的值小的时候,进行向右移动数值
a[i+1]=a[i];
i--;//从右向左依次遍历每个数
if(i<0){
break;
}
}
a[i+1]=temp;//最后将temp插入到空出来的位置上,i+1是因为i--最后多减了一次1,所以此处要加上1
}
print(a);
}
(五)二分法插入排序
算法描述:
◆在直接插入排序的基础上,利用二分(折半)查找算法决策出当前元素所要插入的位置。
◆二分查找:找到中间元素,如果中间元素比当前元素大,则当前元素要插入到中间元素的左侧;否则,中间元素比当前元素小,则当前元素要插入到中间元素的右侧。
◆找到当前元素的插入位置i之后,把i和high之间的元素从后往前依次后移一个位置,然后再把当前元素放入位置i。
代码演示:
/**
* high为何要-1? low为何要+1?
* (1)Java中有个规范:左闭右开[ low , high )。
* (2)经过二分法得到了mid,分为两个区间:[low,mid) 、[mid, high)。
* (3)可以看出:(temp<=a[mid])? high=mid-1:low=mid+1;
*/
public static void dichotomy(int[] a){
for(int i=0;i<a.length-1;i++){
int temp=a[i+1];
int low=0;
int high=i;
while(low<=high){ //循环条件:当low<=high时候进行比较取值
int mid=(low+high)/2;
if(temp<=a[mid]){ //确定下一次high、low的值
high=mid-1;
}else{
low=mid+1;
}
}
int j=high; //确定需要下次替换的位置
for(int k=i;k>j;k--){ //[i , high]之间的所有数右移
a[k+1]=a[k];
}
a[j+1]=temp;
}
print(a);
}
(六)希尔排序
希尔排序又称缩小增量排序,是1959年由D.L.Shell提出来的。
算法描述:
(1)先取定一个小于n的整数gap1作为第一个增量,把整个序列分成gap1组。所有距离为gap1的倍数的元素放在同一组中,在各组内分别进行排序(分组内采用直接插入排序或其它基本方式的排序)。
(2)然后取第二个增量
gap2<gap1
,重复上述的分组和排序。(3)依此类推,直至增量gap=1,即所有元素放在同一组中进行排序为止。
算法分析:
(1)开始时 gap 的值较大, 子序列中的元素较少, 排序速度较快。
(2)随着排序进展, gap 值逐渐变小, 子序列中元素个数逐渐变多,由于前面大多数元素已基本有序, 所以排序速度仍然很快。
(3)分组后n值减小,n²更小,而T(n)=O(n²),所以T(n)从总体上看是减小了。
(4)Gap的取法有多种。 shell 提出取 gap = n/2 ,gap = gap/2 ,…,直到gap = 1。gap若是奇,则gap=gap+1
代码演示:
public static void shellSort(int[] a){
for(int gap=(a.length+1)/2;gap>0;gap/=2){
for(int i=0;i<a.length-gap;i++){
for(int j=i;j<a.length-gap;j+=gap){
if(a[j]>a[j+gap]){
swap(a,j,j+gap);
}
}
}
}
}