一丶java中常见的排序算法总结


注意:荷兰国旗问题和快排的不同在与More值的确定,荷兰国旗取的是length,而快排length-1;

时间复杂度的比较:

快速排序的时间复杂度为 O(nlogn),最坏情况下为 O(n^2)。堆排序的时间复杂度为 O(nlogn),无论最好情况还是最坏情况都是 O(nlogn)。
在这里插入图片描述

1.冒泡排序

思想:每次排序找出当次的最大值,所以只需要进行arr.length-1次大的排序,而在每次大的循环中,需要做arr.length-1-i次小的比较,因为已经确定了i个数的位置放在最后面了。
优化:因为排序过程中,各元素不断接近自己的位置,如果一趟比较下来没有进行过交换,就说明序列有序,因此要在排序过程中设置一个flag判断元素是否进行过交换。从而减少不必要的比较。

 * @Author Mr.Wu
 * @Date 2019/6/23 11:30
 * @Version 1.0
 **/
public class BubbleSort {
    public static void main(String[] args) {
        int[] arr ={3,9,-1,10,2};
        bubbleSort(arr);
        System.out.println("排序之后的数组"+ Arrays.toString(arr));

    }
    public static void bubbleSort(int[] arr){
        int temp =0;
        boolean flag =false;
        for (int i = 0; i <arr.length-1 ; i++) {
            for (int j = 0; j <arr.length-1-i ; j++) {
                if (arr[j] > arr[j+1]) {
                    flag= true;
                    temp = arr[j];
                    arr[j] =arr[j+1];
                    arr[j+1] =temp;
                }
            }
            if(!flag){
                break;  //在一趟排序中,一次交换都没有发生过。则直接退出
            }else{
                flag =false;
            }
            
        }
    }
}

2.选择排序

 * @Author Mr.Wu
 * @Date 2019/6/24 11:09
 * @Version 1.0 选择排序。
 **/
public class SelectSort {
    public static void main(String[] args) {
        int [] arr ={3,5,-1,67,6};
        selectSort(arr);
        System.out.println(Arrays.toString(arr));
    }
    public static void selectSort(int[] arr){
        for (int i = 0 ; i <arr.length-1; i++) {
            int minIndex =i;
            int min=arr[i];
            for (int j = i+1; j <arr.length ; j++) {
                if(min>arr[j]){
                    min=arr[j];
                    minIndex =j;
                }
            }
            if(minIndex!=i){
                arr[minIndex]=arr[i];
                arr[i]=min;
            }

        }
    }
}

代码优化之后:

public static void selectionSort(int[] arr){
	if(arr==null||arr.length<2){
			return;
	}
for(int i=0;i<arr.length-1;i++){
	int minIndex=i;
	for(int j=i+1;j<arr.length;j++){
		minIndex=arr[j]<arr[minIndex]?j:minIndex;
		}
	swap(arr,i,minIndex);
	}
}
public static void swap(int[] arr,int i,int j){
	int temp=arr[i];
	arr[i]=arr[j];
	arr[j]=temp;
}

计数排序

时间复杂度是O(n+k),空间复杂度O(n+k)
量大但是范围比较小

  • 某大型企业数万名员工年龄排序
  • 如何快速得知高考名次
/**
 * @Description TODO
 * @Author Mr.Wu
 * @Date 2020/6/17 21:19
 * @Version 1.0
 **/
public class CountSort {
    public static void main(String[] args) {
        int[] arr = {2,4,2,3,7,1,1,0,0,5,6,9,8,7,4,0,9};
        int[] result = sort(arr);
        System.out.println(Arrays.toString(result));
    }
    private static int[] sort(int[] arr){
        //1.首先开辟一个存放结果的一个数组
        int[] result = new int[arr.length];
        //2.开辟范围的数组
        int[] count = new int[10];
        for (int i = 0; i < arr.length; i++) {
            count[arr[i]]++;
        }
        for (int i = 0,j = 0 ; i < count.length; i++) {
            //只要桶中还有值,依次取出来。
            while(count[i]-- > 0){
                result[j++] = i;
            }
        }
        return result;
    }
}

优化之后的计数数组

在这里插入图片描述

public class CountSort {
    public static void main(String[] args) {
        int[] arr = {2,4,2,3,7,1,1,0,0,5,6,9,8,7,4,0,9};
    
        int[] result = sort(arr);
        System.out.println(Arrays.toString(result));
    }
    private static int[] sort(int[] arr){
        //1.首先开辟一个存放结果的一个数组
        int[] result = new int[arr.length];
        //2.开辟范围的数组
        int[] count = new int[10];
        for (int i = 0; i < arr.length; i++) {
            count[arr[i]]++;
        }
        System.out.println(Arrays.toString(count));
        //3.获取一个累加数组,累加数组的值就是当前count
        for (int i = 1; i < count.length ; i++) {
            count[i] = count[i] +count[i-1];
        }
        System.out.println(Arrays.toString(count));
     
        //4.倒序处理
        for (int i = arr.length-1; i >=0 ; i--) {
            result[--count[arr[i]]] = arr[i];

        }
        return result;
    }
}

3.基数排序

基数排序属于稳定性排序,是加粗样式效率较高的稳定性排序。同时也是桶排序的扩展。
基本思想:将所有带比较数值统一为同样的位数长度,数位较短的数前面补零。然后从最低位开始,依次进行一次排序,这样从最低位排序一直到最高位排序完成以后,数列就变成了一个有序序列。
在这里插入图片描述
在这里插入图片描述

* @Author Mr.Wu
 * @Date 2019/7/5 9:49
 * @Version 1.0
 **/
public class RadixSort {
    public static void main(String[] args) {
        int[] arr ={53,3,542,748,14,214};
            radixSort(arr);
    }
    //基数排序算法。基数排序是使用空间换时间的经典算法。
    public static void radixSort(int[] arr){
        //1.得到数组中最大的数的位数
        int max =arr[0];
        for (int i = 1; i < arr.length; i++) {
            if(arr[i]>max){
                max=arr[i];
            }
        }
        //得到最大数是几位数
        int maxLength=(max+"").length();

        int[][] bucket = new int[10][arr.length];
        //为了记录每个桶中,实际存放了多少个数据,我们定义一个一维数组来记录各个桶的每次放入的数据个数
        //bucketElementConts[0],记录的就是bucket[0]桶的放入数据的个数
        int[] bucketElementCounts = new int[10];
        for (int i = 0,n=1; i < maxLength; i++, n*=10) {
            //(针对每个元素的对应位进行排序),第一次是个位,第二次是十位,第三次是百位
            for (int j = 0; j <arr.length ; j++) {
                int digitOfElement = arr[j] /n %10; //取出每个元素中对应的位数
                bucket[digitOfElement][bucketElementCounts[digitOfElement]] =arr[j];
                bucketElementCounts[digitOfElement]++;
            }
            //按照这个桶的顺序(一维数组的下标依次取出数据,放入到原来的数组)
            int index =0;
            //遍历每一个桶,并将桶中的数据,放入到原数组中去。
            for (int k = 0; k <bucketElementCounts.length ; k++) {
                //如果桶中有数据,我们才放入到原数组中
                if(bucketElementCounts[k]!=0){
                    //循环该桶即第k个桶(即第k个一维数组),放入。
                    for (int l = 0; l <bucketElementCounts[k] ; l++) {
                        arr[index++] =bucket[k][l];
                    }
                }
                //第i+1轮处理后,需要将每个bucketElementConunts[k]=0
                bucketElementCounts[k]=0;
            }
            System.out.println("第"+(i+1)+"轮,对数的排序处理arr="+ Arrays.toString(arr));
        }

    }

}

排序结果如下:
在这里插入图片描述

通过计数排序优化后的基数排序:

 * @Author Mr.Wu
 * @Date 2020/6/17 20:28
 * @Version 1.0
 **/
public class RadixSort {
    public static void main(String[] args) {
        int[] arr = {421,240,115,532,305,430,124};
        int[] result = sort(arr);
        System.out.println(Arrays.toString(result));
    }
    public static int[] sort(int[] arr){
        int[] result = new int[arr.length];
        int[] count = new int[10];
        for(int i = 0;i < 3;i++){
            int division = (int)Math.pow(10,i);
            System.out.println(division);
            for (int j = 0; j < arr.length; j++) {
                int num = arr[j]/division % 10;
                System.out.println(num + "");
                count[num]++;
            }
            System.out.println();
            System.out.println(Arrays.toString(count));
            for (int m = 1; m < count.length ; m++) {
                count[m] = count[m] + count[m-1];
            }
            System.out.println(Arrays.toString(count));
            for (int n = arr.length - 1; n >= 0; n--) {
                int num = arr[n]/division % 10;
                result[--count[num]] = arr[n];
            }
            System.arraycopy(result,0,arr,0,arr.length);
            Arrays.fill(count,0);
            }
        return  result;
        }
    }

4.归并排序

.归并排序,先分在治,充分利用了递归的思想。
在这里插入图片描述
下面是治的示意图:
在这里插入图片描述

* @Author Mr.Wu
 * @Date 2019/7/2 9:32
 * @Version 1.0
 **/
public class MergetSort {
    public static void main(String[] args) {
        int[] arr={8,4,5,7,1,3,6,2};
        int[] temp = new int[arr.length];
        mergeSort(arr,0,arr.length-1,temp);
        System.out.println("归并排序后"+ Arrays.toString(arr));
    }

    //分开+合并
    public static void mergeSort(int[] arr,int left,int right,int[] temp){
        if(left<right){
            int mid = (left+right)/2;
            //向左递归进行分解
            mergeSort(arr,left,mid,temp);
            //向右递归进行分解
            mergeSort(arr,mid+1,right,temp); //最后到了分的最后,然后在归回去,一步一步的合起来
            //到合并
            merge(arr,left,mid,right,temp);
        }
    }
    /**
     * @param mid:中间索引
     * @param left:左边有序序列的初始索引
     * @param right:右边索引
     * @param temp:中转数组
     */
    public static void merge(int[] arr,int left ,int mid,int right,int[] temp){
        int i = left;
        int j =mid+1; //初始化j,右边有序序列的初始索引
        int t =0;  //指向temp数组的当前索引
        //1.先把左右两边(有序)的数据按照规则填充到temp数组,直到左右两边的有序序列,有一边处理完成为止
        while (i<=mid&&j<=right){
            if(arr[i]<=arr[j]){
                temp[t]=arr[i];
                i+=1;
                t+=1;
            }else{
                temp[t]=arr[j];
                j+=1;
                t+=1;
            }
        }
        //2.把有剩余的数据的一遍的数据依次全部填充到temp中
        while(i<=mid){
            temp[t]=arr[i];
            t+=1;
            i+=1;
        }
        while(j<=right){
            temp[t]=arr[j];
            t+=1;
            j+=1;
        }
        //3.将temp数组的元素拷贝到arr
        t=0;
        int tempLeft = left;
        while(tempLeft<=right){ //第一次合并tempLeft=0,right=1//tempLeft= 2 right =3//tempLeft =0,right=3;
            //最后一次tempLeft=0,right =7;
            System.out.println("tempLeft="+tempLeft+"right"+right);
            arr[tempLeft]=temp[t];
            t+=1;
            tempLeft+=1;
        }

    }
}

优化之后 .思路是一样的。将样本量分成两个部分,现将左边和右边分别进行排序。。。merge函数===用两个指针,分别指向,最左边和中间后面一个,然后进行比较。小的就放在临时数组中,然后将指针右移,直到有一个指针移除边界之后,然后在把剩余的数组都拷贝到临时数组中,这样数组就排完序了,然后在将原数组进行替换。
注意:最后这种基于while的运算,不能采用三目运算符。
思路:
归并排序(Merge Sort)是一种稳定的、基于分治思想的排序算法,它的核心思想是将待排序数组划分成若干等长的子数组,对子数组进行排序,最后合并完成整个排序过程。

具体来说,归并排序的过程如下:

分治:将待排序数组递归分成左右两个子数组,直到子数组中只有一个元素。

合并:合并左右两个子数组,使得合并后的数组仍然有序。具体方法是将两个已经有序的子数组合并成一个有序的大数组。

递归结束条件:当待排序数组的长度为1时,递归结束。


public static void mergeSort(int[] arr,int l,int r){
if(l==r){  //终止条件,此时只有一个数,就不用排了。
	return;
	}
int mid=(l+r)/2;
mergeSort(arr,l,mid);
mergeSort(arr,mid+1,r);
merge(arr,l,mid,r);
}
public static void merge(int[] arr,int l,int mid,int r){
	int[] help =new int[r-l+1];
	int i=0;
	int p1=l;
	int p2=mid+1;
	while(p1<=mid&&p2<=R){
		help[i++]=arr[p1]<arr[p2]?arr[p1++]:arr[p2++];
	}
	while(p1<mid){
		help[i++]=arr[p1++];
			}
	while(p2<=r){
		help[i++]=arr[p2++];
		}
	for(int i=0;i<help.length;i++){
		arr[l+i]=help[i];
		}
	}

5.快排和堆排

5.1 小和问题(可以由上面的归并排序引出)

在这里插入图片描述
思路:
1.其实可以转换成右边比当前数(curr)大的有几个(i)数,此时的小和就是i*curr;
2.然后利用归并排序来进行解决问题。
在这里插入图片描述

public class Code_12_smallSum{
    
    public static int smallSum(int[] arr){
        if(arr=null||arr.length<2){
            return ;
        }
        return mergeSort(arr,0,arr.length-1);
    }
    public static int mergeSort(int[] arr,int l ,int r){
        if(l==r){
            return ;
        }
       int mid = l+(r-l)>>1;  //这种写法是等价于 int mid=(l+r)/2;并且是防溢出的,同时位运算相对于算数运算较快。
       //因为每次治的产生的小和都需要加在一起,所以需要写成这样。
        return mergeSort(arr,l,mid)+mergeSort(arr,mid+1,r)+merge(arr,l,mid,r);
    }
    public static int merge(int[] arr,int l,int mid,int r){
        int[] help =new int[r-l+1];
        int mid =(l+r)/2;
        int res = 0;
        int p1=l;
        int p2=mid+1;
        //还是使用两个指针,然后相比较,较小的放入到临时数组中,同时指针向右移动,直到有一边的指针移出,然后将剩余的数组全部放入到临时数组中。
        //注意:这里的res;比较两边的值,看右边的值,因为已经是排好序的了。如果左边的这个指针小于右边的指针,那么右边的所有的数都是小和数。需要全部加起来。
        while(p1<=mid&&p2<=r){
            res +=arr[p1]<arr[p2]?arr[p1]*(r-p2+1):0;
            help[i++] = arr[p1]<arr[p2]?arr[p1++]:arr[p2++];
        }
        while(p1<=m){
            help[i++]=arr[p1++];
        }
        while(p2<=r){
            help[i++]=arr[p2++];
        }
        for(int i=0;i<help.length;i++){
            arr[l+i] =help[i];
        }
        return res; 
    }
}

5.2 荷兰国旗问题

在这里插入图片描述
直接看问题2 ,然后问题1就是2的简化:
思路:
在这里插入图片描述
情况1:curr==num的时候直接跳下一个,不管他
情况2: curr<num:将curr与小于区域的下一个数进行交换,然后小于区域向前扩一个位置。curr++,++less;
情况3:curr>num: 将curr与大于区域的上一个数进行交换,然后大于区域向前扩一个位置,然后在判读(这里还需要判断)
当less和more撞上了,整个过程结束。

 public static int[] partition(int[] arr,int l,int r,int num){
        int less= l-1;
        int more =r+1;
        int curr=l;
        while(curr<more){
            if(arr[curr]<num){
                swap(arr,++less,curr++); //先将小于区域的前一个位置与curr位置交换,然后当前位置后移一位。主语++i和i++之间的关系
            }else if(arr[curr]>num){
                swap(arr,--more,curr); //先将大于区域前的一个数与当前位置交换,但是当前位置不变进行判断
            }else{
                curr++;
            }
        }
        return new int[] {less+1,more-1};
    }
    public static void swap(int[] arr,int i,int j){
        int temp =arr[i];
        arr[i]=arr[j];
        arr[j]=temp;
    }

5.3快速排序(用荷兰国旗问题改进)

思路:选取数组的最后一个为参照。小于区域在左边,等于区域在中间,大于区域在右边。然后返回的是等于区域的位置,然后根据等于区域的位置然后进行递归。(上面比较的时候用了一个index比较好理解,与下面的这种用l代替是一样的。)
注意:几次都含糊不清的地方,while(l<more);
思路:
快速排序采用分治法(Divide and Conquer)的思想,具体过程如下:

选取一个基准点(pivot)作为分界点。可以从数列中随机选取一个数,或者选择数列的第一个数或最后一个数作为基准点。

比基准点小的数放在左边,比基准点大的数放在右边。对于每个元素,比较它和基准点的大小关系,如果比基准点小,则将其放在基准点的左边,否则放在右边。

对左右两边的子数列进行递归排序。递归结束的条件是子数列长度为1或0,此时子数列已经有序。

   public static void quickSort(int[] arr,int l,int r){
        if(l<r){
        	//swap(arr,l+(int)(Math.random()*(r-l+1)),r); 如果加上这一段就是随机快排。
            int[] p =partition(arr,l,r);//等于区域的位置,p中固定只有两个元素。
            quickSort(arr,l,p[0]-1);  //对小于区域进行排序,因为最后返回的是相等数的位置,所以需要减一
            quickSort(arr,p[1]+1,r);   //对大于区域进行排序,同理是相等数的位置,所以需要加+1
        }
    }
    
    public static int[] partition(int[] arr,int l,int r){
        int less=l-1;
        int more=r; //因为我们选取的就是最后一个元素,作为比较,所以不参与。右边区域直接到r
        while(l<more){  //这里的l相当于上面的index,用来进行遍历使用的。
            if(arr[l]<arr[r]){
                swap(arr,++less,l++);
            }else if(arr[l]>arr[r]){
                swap(arr,--more,l);
            }else{
                l++;
            }
        }
        swap(arr,more,r); //因为最初,最后面的一个元素没有参与比较,那么最后需要进行交换。
        return new int[] {less+1,more}; // 我们需要返回一个包含等于区域的起始和结束位置的数组,即return new int[] {less+1,more}。
    }

5.4快速排序(最古老的思路,最好还是采用上面一种)

基本思想:快速排序是对冒泡排序的一种改进。它是通过一趟排序将要排序的数据分割成独立的两个部分,其中一部分的所有数据比另外一部分的所有的数据都要小,然后按照此方法对这两部分分别在进行快速排序,整个排序过程可以递归进行,以此来到达整个数据变成有序数列。
在这里插入图片描述

* @Author Mr.Wu
 * @Date 2019/6/28 10:41
 * @Version 1.0
 **/
public class QuickSort {
    public static void main(String[] args) {
        int[] arr={-9,0,32,-78,0,5,-6,-9};
        quickSort(arr,0,arr.length-1);
        System.out.println("arr="+ Arrays.toString(arr));

    }
    public static void quickSort(int[] arr,int left,int right){
        int l =left;
        int r= right;
        int pivot = arr[(left+right)/2];
        int temp = 0;
        //while循环的目的是让比pivot值小放到左边
        while(l<r){
            //在pivot的左边一直找,找到大于的等于pivot值,才退出下面这个循环。
            while(arr[l]<pivot){
                l +=1;
            }
            while(arr[r]>pivot){
                r-=1;
            }
            //如果l>=r说明pivot的左右两的值,已经按照左边全部是小于等于pivot,右边全是是大于等于pivot的值。
            if(l>=r){
                break;
            }
            temp = arr[l];
            arr[l] =arr[r];
            arr[r]=temp;
            //如果交换完后,发现这个arr[l] ==pivot值相等--,前移
            if(arr[l]==pivot){
                r-=1;
            }
            if(arr[r]==pivot){
                l+=1;
            }
            if(l==r){  //如果l==r,必须l++,r--,否则出现栈溢出。
                l+=1;
                r-=1;
            }
            //向左递归
            if(left<r){
                quickSort(arr,left,r);
            }
            if(right>l){ //向右递归。
                quickSort(arr,l,right);
            }
        }
    }
}

5.5堆排序

堆 和 数组之间的关系图解,点击这里
思路:首先将数组形成一个大根堆,然后将堆顶的数和最后一个数,进行交换,然后调整位置,使剩余的也变成一个大根堆。
左孩子节点 = 父节点2 +1;
右孩子节点 = 父节点
2+2;
父节点 = (左(右)孩子节点-1)/2
注意:几次都忘记写在做向下调整的时候,倒数第二步的,index = largest;
参考文章,点击这里

public static void heapSort(int[] arr){
	if(arr==null||arr.length<2){
	return;
	}
	
	for(int i=0;i<arr.length;i++){
		heapInsert(arr,i);
		}
	int heapSize =arr.length;
	swap(arr,0,--heapSize);  //先和最后一个位置的进行交换,然后继续下面的操作
	while(heapSize>0){
		heapify(arr,0,heapSize);	
		swap(arr,0,--heapSize);
		
			}
	}
}
//当值变小之后,每次找出最大值,然后向下沉淀
public static void heapify(int[]arr,int index,int heapSize ){
	 // index位置所在节点的左子节点位置
        int left = index * 2 + 1;
        // 左子节点不越界
        while (left < heapSize) {
            // (left+1)为右子节点的下标,如果右子节点不越界 && 左子节点的值 < 右子节点的值
            // largest就表示两个子节点中值较大节点在数组中的下标
            int largest = left + 1 < heapSize && arr[left] < arr[left + 1] ? left + 1 : left;
            // 当前节点的值和较大子节点的值比较,返回较大节点值的下标
            largest = arr[index] > arr[largest] ? index : largest;
            // 如果是本身较大,则不用下沉,此位置就是最终位置
            if (largest == index) {
                break;
            }
            // 较大的不是本身,则和较大的节点交换位置
            swap(arr, index, largest);
            // 修改当前下标为较大节点的下标
            index = largest;
            // 找当前下标位置对应的左子节点下标
            left = 2 * index + 1;
        }
	}
//形成大跟堆,每个位置都和它的父亲节点进行对比,如果比父亲节点大就交换位置。
public static void heapInsert(int[] arr,int index){
 	while(arr[index]>arr[(index-1)/2]){  
 	swap(arr,index,(index-1)/2);
 	index =(index-1)/2;  //这里必须还要往上跑,然后进行比较交换。
 	}
 	

6.插入排序:

插入排序的基本思想是:把n个待排序的元素看成一个有序表和一个无序表,开始时有序表中只包含一个元素,无序表中包含有n-1个元素,排序过程中每次从无序表中取出第一个元素,比较的方式是倒序,也就是先和n-1比较,如果n比n-1小,则互换位置,来到n-1的位置,然后n-1和n-2比,一直比到大于等于即可。(因为前面的元素是排序好的,所以比较一遍即可)

6.1插入排序方法1:(交换法)

/**
 * @Description TODO
 * @Author Mr.Wu
 * @Date 2019/6/26 11:25
 * @Version 1.0
 **/
public class InsertSort2 {
    public static void main(String[] args) {
            int[] arr = {101,34,119,1,-1,89};
            insertSort(arr);
    }
    public static void insertSort(int[] arr){
        int j ;
        for (int i = 1; i <arr.length ; i++) {  //需要排序的次数

            for ( j = i-1; j>=0&&arr[j]>arr[j+1]; j--) { //取i前面的所有元素和i元素进行比较,如果i-1大于i,则互换位置,以此类推。
                int temp=arr[j];
                arr[j]=arr[j+1];
                arr[j+1]=temp;
            }

            System.out.printf("第%d次排序之后的结果"+Arrays.toString(arr),i);
            System.out.println();
        }
    }
}

6.2插入排序方法2:(移动法)

 * @Description TODO
 * @Author Mr.Wu
 * @Date 2019/6/25 10:26
 * @Version 1.0
 **/
public class InsertSort {
    public static void main(String[] args) {
        int[] arr={101,34,119,1,-1,89};
        insertSort(arr);

    }
    public static  void insertSort(int[] arr){

        for (int i = 1; i <arr.length ; i++) {

           int insertVal=arr[i];
            int insertIndex=i-1;

            while(insertIndex>=0&&insertVal<arr[insertIndex]){
                arr[insertIndex+1]=arr[insertIndex];
                insertIndex--;
            }
                arr[insertIndex+1]=insertVal;
            System.out.printf("第%d次排序之后的结果"+Arrays.toString(arr),i);
            System.out.println();

        }
    }
}

结果都如下所示:

1次排序之后的结果[34, 101, 119, 1, -1, 89]2次排序之后的结果[34, 101, 119, 1, -1, 89]3次排序之后的结果[1, 34, 101, 119, -1, 89]4次排序之后的结果[-1, 1, 34, 101, 119, 89]5次排序之后的结果[-1, 1, 34, 89, 101, 119]

7.希尔排序

7.1:采用交换法,进行希尔排序:

* @Author Mr.Wu
 * @Date 2019/6/26 14:50
 * @Version 1.0
 **/
public class ShellSort {
    public static void main(String[] args) {
        int[] arr = {8,9,1,7,2,3,5,4,6,0};
        shellSort(arr);
        
    }
    public static void shellSort(int[] arr){
        for (int gap = arr.length/2; gap >0 ; gap/=2) { //步长逐渐在减小
            for (int i = gap; i <arr.length ; i++) { //在同一步长内,需要排序的次数
                //同一步长内排序方式就是插入排序,使用的是第一种
                for ( int j = i-gap; j>=0&&arr[j]>arr[j+gap]; j-=gap) {
                      int temp = arr[j];
                      arr[j]=arr[j+gap];
                      arr[j+gap] =temp;
                }
            }
            System.out.printf("步长为%d的排序结果为"+ Arrays.toString(arr),gap);
            System.out.println();
        }
    }
}

7.2采用移动法进行希尔交换

 * @Author Mr.Wu
 * @Date 2019/6/26 15:40
 * @Version 1.0
 **/
public class ShellSort2 {
    public static void main(String[] args) {
        int[] arr = {8,9,1,7,2,3,5,4,6,0};
        shellSort2(arr);

    }
    public static void shellSort2(int[] arr){
        for (int gap = arr.length/2; gap >0 ; gap/=2) { //步长逐渐在减小
          //从第gap个元素,逐个对其所在的组进行直接插入排序
            for (int i = gap; i <arr.length ; i++) {
                int j=i;  //保存了插入数的位置
                int temp =arr[j];  //保存了插入的数
                    while(j-gap>=0&&temp<arr[j-gap]){
                        arr[j] =arr[j-gap];
                        j-=gap;
                    }
                    arr[j] =temp;
            }
            System.out.printf("步长为%d的排序结果为"+ Arrays.toString(arr),gap);
            System.out.println();
        }
    }
}

结果如下:

步长为5的排序结果为[3, 5, 1, 6, 0, 8, 9, 4, 7, 2]
步长为2的排序结果为[0, 2, 1, 4, 3, 5, 7, 6, 9, 8]
步长为1的排序结果为[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

总结:通过验证移动法的效率远高于交换法。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值