常见的算法:二分法查找,冒泡排序和选择排序

今天主要说一下常见的算法 ,于是我百度了一下点进那 “ 牛逼 ” 的知乎看了一眼 ,完蛋了 ,这都是些神马 ??? 我怎么一个都不会呢 ,我要的可是那种很常见的算法啊 ,好吧 ,无形中又被深深的伤了一刀 ,好在我迅速调节状态 。管他呢 ,我就按照自己 low 的来吧 。进入正题 ,我要说的几种算法就是二分法查找 ,冒泡排序和选择排序 。以数组为例 ,谈谈它们在 Java 中的实现 。

二分法查找 ,举个例子说明一下 ,我们在玩猜数字游戏的时候经常会用到 。小明给出数的范围 ,0 ~ 100 ,我们猜 50 ,小明回答说 “ 大了 ” ,那我们会接着猜 25 ,就这样我们一次次的逼近了真相 。这就是二分法的思想 。也可以说是分治的思想 ,分而治之 ,逐一攻破 。我们同样也可以将这种思想应用到有序数组的查找上 。我们可以拿数组中间的数和待查找元素进行比较 ,其过程类似与猜数字 ,变得就是 “ 中间 ” 位的那个数 。最终我们可以找到目标元素 。方法实现 :

private static int binarySearch(int[] list,int target) {
        int low = 0;
        int high = list.length - 1;
        //直到low>high时还没找到关键字就结束查找,返回-1
        while(low<=high){
        int mid = (low+high) / 2;
        if(target < list[mid]){
            high = mid - 1;
        }
        else if(target > list[mid]){
            low = mid + 1;
        }
        else if(target == list[mid]){
            return mid;
            }
        }
        return -1;
    }

冒泡排序 ,想象一下鱼儿在水中吐了一个泡 ,在向上的过程中 ,是不是在越变越大 。其实冒泡排序的思想也就是这样的 。给你 n 个数 ,我们用第一个数和第二个数进行比较 ,大的那个就放第二位 ,然后第二位和第三位比较 ,大的那个放在第三位 ,依次比下去 ,待到和最后一个比较结束 ,我们就能得到这 n 个数中最大的那个 ,且放在最后一个位置上 。( 这要是不明白就回头再读一遍 ) 这样一轮比较结束我们得到一个最大的数 ,第二轮我们再进行比较 ,同理 ,可以得到剩余 n – 1 个数中最大的数 。且放在倒数第二位 ,这就就是内层 for 循环条件 – 1 的原因 ,因为没必要和上一轮的最后一个数进行比较嘛 。方法实现 :

public static void bubbleSort(int[] arr) {
     /* * 外面的for循环决定一个长度为 n 的数据要比较多少轮才能完成排序。 * 里面的for循环决定每次一轮循环中要做多少次才能结束。 */
     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]){
                int temp = arr[j]
                arr[j] = arr[j + 1]
                arr [j + 1] = temp 
             }
         }
     } 
}

PS . 只需要换一个符号 ,就可以得到从大到小的序列 。

快速排序 ,快速排序是对冒泡排序的一种改进 。它的基本思想是将要排序的数据分割成独立的两部分 ,其中一部分的所有数据都比另外一部分的所有数据都要小 。然后在按照此方法对两部分数据分别进行快速排序 ,最终得到一个有序的序列 。需要说明的是 ,快速排序的平均时间复杂度是 O(nlogn) 。但是时间复杂度还是 O(n^2) ,因为时间复杂度是按照最坏结果来计算的 。为了方便理解 ,使用一组数据模拟一下排序的过程 。

假设要排的数组为:int[] a = { 5 2 8 9 2 3 4 9 };

选择 key = 5, 开始时 i = 0j = 7

下标         0    1    2    3    4    5    6    7

开始         5    2    8    9    2    3    4    9
            i                                  j  

第一次找     5    2    8    9    2    3    4    9
                      i                   j

交换:       5    2    4    9    2    3    8    9 
                      i                   j

第二次找     5    2    4    9    2    3    8    9
                           i         j

交换:       5    2    4    3    2    9    8    9
                           i         j

第三次找     5    2    4    3    2    9    8    9
                               ij

调整key:    2    5    4    3    5    9    8    9
                               ij

方法实现 :

private static void quickSort(int[] a, int low, int high) {  
        //找到递归算法的出口 
        if( low > high) {
            return;
        }
        int i = low;  
        int j = high;  
        //默认 key
        int key = a[low];  
        //开始一趟排序
        while( i < j) {
            //先从右往左找到第一个小于 key 的数 ,
            //这么做是因为在与 key 值交换的时候,保证了交换的数小于现有的 key 值
            //若是大于的话,j 指针就会继续向左移动 。
            while(i<j && a[j] > key){  
                j--;  
            }
            //从左往右找到第一个大于等于 key 的数 
            while( i<j && a[i] <= key) {  
                i++;  
            }
            //交换,达到以 key “分治” 的效果
            if(i<j) {
                int temp = a[i];  
                a[i] = a[j];  
                a[j] = temp;  
            }  
        }
        // 当 i = j 时,调整 key 的值为 a[i] == a[j] 
        int temp = a[i];  
        a[i] = a[low];  
        a[low] = temp;  
        //对 key 左边的数快速排序
        quickSort(a, low, i-1 );  
        //对 key 右边的数快速排序 
        quickSort(a, i+1, high);  
}

后记 :不得不说 ,这些简单的算法我都没有很熟悉 ,只能是那种原理清楚 ,但是实现起来却是磕磕绊绊的状态 。还有 ,以上给出的实现是可以进一步优化的 ,记得之前在面试的时候被问到过冒泡排序的问题 ,现场也被问到过如何优化 。

    原文作者:查找算法
    原文地址: https://blog.csdn.net/yujikui1/article/details/81045236
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞