JAVA之各种排序算法(冒泡、选择、快排、二分法详细过程)

版权声明:本文为博主原创文章,未经博主允许不得转载。https://blog.csdn.net/qq_37757008/article/details/81408567 https://blog.csdn.net/qq_37757008/article/details/83316636

掌握算法是作为程序员的基本必备素质,而排序也是各种算法的基础,虽说java帮我们封装好了各种数据类型的排序方法,可是我们还是要知道他的原理,下面我就说几种常用的算法及原理;

冒泡排序:

原理:相邻元素两两比较,大的往后放,每一次完毕,最大值出现在了最大索引处;
下面我们用图的方式直观的给大家展示
在这里插入图片描述
从上面的图来看,每一次比较交换的算法应该是

/for(int i=0;i<arr.length-1;i++){
 		if(arr[i]>arr[i+1]){
    			//值交换
       			 int t=arr[i];
 				 arr[i]=arr[i+1];
				 arr[i+1]=t;
		  }
}

首次比较五个数我们只需要比较四次;每多一次排序,少比较一次,因此i<arr.length-1;而这个过程我们需要五次的重复,每次我们给循环条件 -1;而这也是可以简化的,所以最后我们优化过后的算法为:

private static void sort(int[] arr) {
        for(int j=0;j<arr.length;j++){
            for (int i = 0; i <  arr.length - 1 -j ; i++) {
                if (arr[i] > arr[i + 1]) {
                    //值交换
                    int t = arr[i];
                    arr[i] = arr[i + 1];
                    arr[i + 1] = t;
                }
            }
        }
  }

选择排序:

原理:每一次那一个元素,和剩余的元素挨个去比较,经过第一遍比较,那么最小的元素,或移动到最前面去;
在这里插入图片描述

 for (int i = index + 1; i < arr.length; i++) {
                if (arr[index] > arr[i]) {
                	//值交换
                    int t = arr[index];
                    arr[index] = arr[i];
                    arr[i] = t;
                }
            }

选择排序就是每次选择一个数和其余的数一一进行比较,比他大的不动,比他小的两者交换;第一次我们就是选择第一个数为基准,它作为index和其余的比较,而我们第一个比较的数就是第二个数,应为自己和自己比较并没有意义;然后循环比较,每次变量 +1;以上的只是第一次比较,当比较完后,我们换第二个数为基准,即index+1;所以我们将其优化为:

private static void sort2(int[] arr) {
        for (int index = 0; index < arr.length - 1; index++) {
            for (int i = index + 1; i < arr.length; i++) {
                if (arr[index] > arr[i]) {
                    int t = arr[index];
                    arr[index] = arr[i];
                    arr[i] = t;
                }
            }
        }
    }

在外围再加一层循环,它起到的作用就是每次比较过后index自加;


快速排序:

原理:快速排序的原理就是分治法;即先比大小,再分区,然后分而治之;
从数组中取出一个数,作为基准;然后分区,选择出比这个数大的数放到它的右边,比这个数小的数放到他的左边;然后分别对左右分区进行分区,直到每个分区只剩一个数;
而他的实现思想可以叫做挖坑填数;什么意思呢?
1.将基准数挖出,形成坑位一;
2.先从后向前找比基准数小的数,找到后挖出它,形成新坑位,将它填到之前的坑位中;
3.然后由前向后找比基准数大的数,找到后挖出它,将他填到之前的坑位中;
4.分号区后,重复之前的2、3步骤;

第一次分析挖坑填数后的结果如下图:
在这里插入图片描述
代码实现:
首先我们需要给序列的起始位置和末尾位置,以此确定每次从前向后和从后向前比较的起点;
int i = start;
int j = end;
然后定义基准位置;
int x =arr[i];
最外围的循环条件为i < j,即起点位置小于终点位置,因为我们最后如果起点位置和终点位置一样时,每个分区就只剩一个数了,这样就完成了排序;同时我们不知道这个过程需要循环多少次,于是用while()循环方法;
while(i < j){}
然后我们就分开从左到右和从右到左的两部分;
从后往前:
while (i<j&&arr[j]>x){
j–;
}
if(i<j){
arr[i]=arr[j];//挖坑填数
i++; //因为接下来我们要从前往后找了,我们顺遍让i递增一下
}
从前往后:
while (i < j && arr[i] <= x) {
i++;
}
if (i < j) {
arr[j] = arr[i];//挖坑填数
j–; //因为接下来我们要从后往前找了,我们顺遍让j递减一下
}
最后我们把基准数填到最后的位置:
arr[i]=x;
同时返回基准数的位置,return i;

我们得到分区完后,基准数的左边的数为左分区的end,基准数的右边的数作为右分区的start;

因此最后我们得到的代码为:

public class QuickSort {

    public static void sort(int[] arr,int start,int end){
        if(start<end){
            //获取中间索引
            int index=getIndex(arr,start,end);
            //对左右两部分进行递归调用
            sort(arr,start,index-1);//排左半边
            sort(arr,index+1,end);//排右半边

        }
    }
    //挖坑填数
    private static int getIndex(int[] arr, int start, int end) {
            int i=start;
            int j=end;
            //定义基准数
            int x=arr[i];
            while (i<j){
                //1.从后往前跟基准数进行比较
                while (i<j&&arr[j] >= x){
                    j--;
                }
                if(i<j){
                    arr[i]=arr[j];//挖坑填数
                    i++;//因为接下来我们要从前往后找了,我们顺遍让i递增一下
                }
                //2.从前往后找
                while (i < j && arr[i] <= x) {
                    i++;
                }
                if (i < j) {
                    arr[j] = arr[i];//挖坑填数
                    j--;//因为接下来我们要从后往前找了,我们顺遍让j递减一下
                }

            }
            //把基准数填到最后一个坑位
            arr[i]=x;

        return i;
    }
}

二分法查找:

注:二分法查找的前提是元素有序;
原理:每次都查中间的那个元素,比较大或者小就能减少一半的元素;
在这里插入图片描述
代码实现:
首先我们定义三个位置的变量:
int minIndex=0;
int maxIndex=arr.length-1;
int midIndex=(minIndex+maxIndex)/2;
最外围循环则是最小值小于最大值
minIndex < maxIndex;
如果要查的元素,正好等于中间索引所对应的元素 直接返回这个中间索引;
if (ele == arr[midIndex]) {
return midIndex;
}
如果你要查找的元素比中间索引所对应的元素大 那么就动最小索引
if (ele > arr[midIndex]) {
minIndex = midIndex + 1;
}
如果你要查找的元素比中间索引所对应的元素小,那么你就动最大索引
if (ele < arr[midIndex]) {
maxIndex = midIndex - 1;
}
最后重新计算中间的索引
midIndex = (minIndex + maxIndex) / 2;

所以最后的代码就是:

private static int findIndex2(int[] arr, int ele) {
        int minIndex=0;
        int maxIndex=arr.length-1;
        int midIndex=(minIndex+maxIndex)/2;
        while (minIndex < maxIndex){
            //如果要查的元素,正好等于中间索引所对应的元素 直接返回这个中间索引
            if (ele == arr[midIndex]) {
                return midIndex;
                //如果你要查找的元素比中间索引所对应的元素大 那么就动最小索引
            } else if (ele > arr[midIndex]) {

                minIndex = midIndex + 1;
                //如果你要查找的元素比中间索引所对应的元素小,那么你就动最大索引
            } else if (ele < arr[midIndex]) {
                maxIndex = midIndex - 1;
            }
            //再重新计算中间索引
            midIndex = (minIndex + maxIndex) / 2;
        }
        return -1;
    }

猜你喜欢

转载自blog.csdn.net/qq_37757008/article/details/83316636