在我们刚刚开始学习代码时,我们的老师会通过一些基本排序来激发我们的编程思维,但是,基本的排序方法(冒泡,选择、插入等)这些方法只是适合于一些较少的数据,当出现大量的数据时使用基本的一些排序方法不单会阻碍程序的性能,严重时会造成系统崩溃!
所以在此我们需要引入高级的排序方法来维护我们程序的性能
一、希尔排序
//希尔排序
public class Shell {
//对数组a中的元素进行排序
public static void sort(Integer [] a){
//根据数据a的长度,确定增长量h的初始值
int h = 1;
while(h<a.length/2){
h=2*h+1;
}
//希尔排序
while (h>=1){
//排序
//找到待插入的元素
for (int i=h;i<a.length;i++){
//把待插入的元素插入有序数列中
for (int j=i;j>=h;j-=h){
//带插入的元素是a[j],比较a[j]和a[j-h]
if (greater(a[j-h],a[j])){
//交换元素
exch(a,j-h,j);
}else {
//待插入元素已经找到合适的位置,结束循环
break;
}
}
}
//减小h的值
h = h/2;
}
}
//比较v元素是否大于w元素
private static boolean greater(int v,int w){
return v>w;
}
//数组元素i和j交换位置
private static void exch(Integer [] a,int i , int j){
Integer temp;
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
二、归并排序
//归并排序,缺点空间换取时间
public class Merge {
//归并所需要的辅助数组
private static Integer [] assist;
//比较v元素是否小于w元素
private static boolean less(int v,int w){
return v<w;
}
//数组元素i与j交换位置
private static void exch(Integer [] a,int i , int j){
Integer t=a[i];
a[i] = a[j];
a[j]=t;
}
//对数组a元素进行排序 等下要排序数组就直接掉用该方法就行了
public static void sort(Integer[] a){
//初始化辅助数组assist;
assist = new Integer[a.length];
//定义一个lo变量,和hi变量,分别记录数组最小的索引和最大的索引
int lo = 0;
int hi=a.length-1;
//调用sort重载方法完成数组a中,从索引lo到索引hi的元素的排序
sort(a,lo,hi);
}
//对数组a中从lo到hi的元素进行排序
private static void sort(Integer [] a,int lo , int hi){
// 如果初始值lo大于数组长度就停止
if (hi<=lo){
return;
}
//对lo到hi之间的数据进行分为两个组
int mid = lo+(hi-lo)/2;
//分别对每一组数据进行排序
sort(a,lo,mid);
sort(a,mid+1,hi);
//再把两个组中的数据进行扫并
merge(a,lo,mid,hi);
}
//对数组中,从lo到mid为一组,从mid+1到hi为一组,对这两组数据进行扫并
private static void merge(Integer [] a,int lo,int mid , int hi){
//定义三个指针
int i=lo;
int p1=lo;
int p2=mid + 1;
//遍历,移动p1指针和p2指针,比较对应索引处的值,找出小的那个,放到辅助数组的对应索引处
while (p1<=mid && p2<=hi){
//比较对应索引处的值
if (less(a[p1],a[p2])){
assist[i++] = a[p1++];
}else {
assist[i++] = a[p2++];
}
}
//遍历,如果p1的指针没有走完,那么顺序移动p1指针,把对应的元素放到辅助数组的对应索引处
while (p1<= mid){
assist[i++] = a[p1++];
}
//遍历,如果p2的指针没有走完,那么顺序移动p2指针,把对应的元素放到辅助数组的对应索引处
while (p2<=hi){
assist[i++] = a[p2++];
}
//把辅助数组的元素拷贝到原数组中
for (int index = lo;index<=hi;index++){
a[index] = assist[index];
}
}
}
三、快速排序
//快速排序,两头查
public class Quick {
//比较v元素是否小于w元素
private static boolean less(Integer v,Integer w){
return v<w;
}
//数组元素i和j交换位置
private static void exch(Integer [] a,int i , int j){
Integer t = a[i];
a[i] = a[j];
a[j] = t;
}
//对数组内的元素进行排序
public static void sort(Integer [] a){
int lo = 0;
int hi = a.length-1;
sort(a,lo,hi);
}
//对数组a中从索引lo索引到hi索引之间的元素进行排序
private static void sort(Integer [] a,int lo, int hi){
//防止lo与hi越界
if (hi<lo){
return;
}
//需要对数组中lo索引到hi索引处的元素进行分组(左子组和右子组)
int partition = partition(a,lo,hi); //返回的是分组的分界值所在的索引,分界值位置变换后的索引
//让左子组有序
sort(a,lo,partition-1);
//让右子组有序
sort(a,partition+1,hi);
}
//对数组a中,从索引lo到索引hi之间的元素进行分组,并返回分组界限对应的索引
public static int partition(Integer [] a,int lo,int hi){
//确定分界值
Integer key = a[lo];
//定义两个指针,分别指向待切分元素的最小索引处和最大索引处的下一个位置
int left = lo;
int right = hi+1;
//切分
while (true){
//先从右往左扫描,移动right指针,找到一个比分界值小的元素,停止
while (less(key,a[--right])){
if (right==lo){
break;
}
}
//再从左往右扫描,移动left指针,找到一个比分界值大的元素,停止
while (less(a[++left],key)){
if (left==hi){
break;
}
}
//判断left>=right,如果是,则证明元素扫描完毕,结束循环,如果不是,则交换元素即可
if (left>=right){
break;
}else {
exch(a,left,right);
}
}
//交换分界值
exch(a,lo,right);
return right;
}
}