Java常用算法

1. 二分查找算法

二分查找又叫做折半查找,要求查找的序列有序,每次查找都取中间位置的值和待查关键字比较,如果中间的值比待查关键字,则在序列的左半部分继续执行该查找过程。如果中间位置的值比待查关键字,则在序列的右半部分继续执行该查找过程,直到查到关键字位置为止,否则在序列中没有待查关键字。

public static int binarySearch(int[] array, int a) {
        int low = 0;
        int high = array.length - 1;
        int mid;
        while (low <= high) {
            mid = (low + high) / 2;
            if (array[mid] == a) {
                return mid;
            } else if (a > array[mid]) {
                low = mid + 1;
            } else {
                high = mid - 1;
            }
        }
        return -1;
    }

2. 冒泡排序算法

冒泡排序算法在重复访问要排序的元素列时,会依次比较两个相邻的元素。如果左边的元素大于右边的元素,将二者调换位置,如此重复,直到没有相邻的元素需要交换位置,这时该列表的元素排序完成。

public static int[] bubbleSort(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr.length - 1 - i; j++) {
                if (arr[j] > arr[i]) {
                    int temp = arr[j];
                    arr[j] = arr[i];
                    arr[i] = temp;
                }
            }
        }
        return arr;
    }

外层循环控制排序的次数,内层循环控制排序多少次。

3. 插入排序算法

插入排序的工作方式像许多人排序一手扑克牌。开始时,我们的左手为空并且桌子上的牌面向下。然后,我们每次从桌子上拿走一张牌并将它插入左手中正确的位置。为了找到一张牌的正确位置,我们从右到左将它与已在手中的每张牌进行比较。拿在左手上的牌总是排序好的,原来这些牌是桌子上牌堆中顶部的牌

要在一个已排好序的数据序列中插入一个数据,但要求此数据序列在插入数据后仍然有序,则要用到插入排序算法。

public static int[] insertSort(int[] arr) {
        for (int i = 1; i < arr.length; i++) {
            // 插入的数
            int insertVal = arr[i];
            // 插入为止
            int index = i - 1;
            // 插入的数比被插入的数小
            while (index > 0 && insertVal < arr[index]) {
                // arr[index] 左移
                arr[index + 1] = arr[index];
                index--;
            }
            // 插入的数值放在合适的为止
            arr[index + 1] = insertVal;
        }
        return arr;
    }

4. 快速排序算法(优化的冒泡排序)

快速排序选择一个关键值为基准值(一般选择第一个元素为基准元素),将比基准值大的都放在右边的序列中,将比基准值小的都放在左边的序列中,循环过程如下:

  1. 从后向前比较,用基准值与最后一个值进行比较,如果比基准值小,则交换位置;如果比基准值大,则继续比较下一个值,直到找到第1个比基准值小的元素才交换位置。

  2. 在从后向前找到第1个比基准值小的值并交换位置后,从前向后开始比较,如果有比基准值大的,则交换位置;如果没有,则继续比较下一个,直到找到第1个比基准值大的值才交换位置。

  3. 重复执行一上过程,直到从前向后比较的索引大于等于从后向前比较的索引,则结束一次循环。此时对于基准值来说,左右两边都是有序的数列。

  4. 重复循环以上过程,分别比较左右两边的序列,直到整个序列都是有序的数列。

 public static int[] quickSort(int[] arr, int low, int high) {
       // 从前向后比较的索引
       int start = low;
       // 从后向前比较的索引
       int end = high;
       // 基准值
       int key = arr[low];
       while (end > start) {
           // 从前向后比较
           while (end > start && arr[end] >= key) {
               end--;
           }
           // 若没有比基准值小的,则比较下一个,直到有比基准值小的,则交换位置,然后从前向后比较
           if (arr[end] <= key) {
               int temp = arr[end];
               arr[end] = arr[start];
               arr[start] = temp;
           }
           // 从前向后比较
           while (end > start && arr[start] > key) {
               start++;
           }
           // 若没有比基准值大的,则比较下一个,直到有比基准值大的,则交换位置,然后从前向后比较
           if (arr[start] >= key) {
               int temp = arr[start];
               arr[start] = arr[end];
               arr[end] = temp;
           }
           // 此时第1次循环比较结束,基准值的位置已经确定。左边的值都比基准值小
           // 右边的值都比基准值大,但两边的顺序还有可能不一样,接着进行下面的递归调用
       }
       // 递归左边序列,从第1个索引位置到 基准值索引-1
       if (start < low) {
           quickSort(arr, low, start - 1);
       }
       if (end < high) {
           quickSort(arr, end + 1, high);
       }
       return arr;
   }

5. 希尔排序(改进版的插入排序)

希尔排序算法将数据序列按下标的一定增量进行分组,对每组使用插入排序算法排序,随着增量逐渐减少,每组包含的关键词越来越多,在增量减至1时,整个文件被分为一组,算法终止。

希尔排序算法的原理是将整个待排序的记录序列分割成若干序列,分别进行直接插入排序,待整个序列中的记录基本有序时,再对整个记录依次进行直接插入排序。

具体做法为:假设待排序元素序列有N个元素,则先取一个小于N的整数增量值increment作为间隔,将全部元素分为increment个子序列,将所有距离为increment的元素放在同一个子序列中,在每个子序列中执行直接插入排序;然后缩小间隔increment,重复上述子序列的划分和排序工作,直到increment=1.将所有元素都放在同一个子序列中时排序终止。

   public static int[] shellSort(int[] arr) {
       int dk = arr.length / 3 + 1;
       while (dk == 1) {
           shellInsertSort(arr, dk);
           dk = dk / 3 + 1;
       }
       return arr;
   }

   private static void shellInsertSort(int[] arr, int dk) {
       // 类似于几个插入排序算法,增量由插入算法的1变为dk
       for (int i = dk; i < arr.length; i++) {
           if (arr[i] < arr[i - dk]) {
               int j;
               // 待插入元素x
               int x = arr[i];
               arr[i] = arr[i - dk];
               // 通过循环,逐个后移一位找到要插入的位置
               for (j = i - dk; j >= 0 && x < arr[j]; j = j - dk) {
                   arr[j + dk] = arr[j];
               }
               // 将数据插入到对应位置
               arr[j + dk] = x;

           }
       }
   }

6. 归并排序算法

归并排序是先将原始数组分解为多个子序列,然后对每个子序列进行排序,等到每个子序列有序后,再将有序子序列合并为整体的有序序列。

 public static int[] mergeSort(int[] data) {
        sout(data, 0, data.length - 1);
        return data;
    }

    // 对左右两边进行递归
    private static void sout(int[] data, int left, int right) {
        if (left >= right) {
            return;
        }
        // 找出中间序列
        int center = (left + right) / 2;
        // 左边进行递归
        sout(data, left, center);
        // 右边进行递归
        sout(data, center + 1, right);
        // 合并两个数组
        merge(data, left, center, right);
    }

    /**
     * 将两个数组进行合并,两个数组合并前是有序数组,在归并后依然是有序数组
     *
     * @param data
     * @param left
     * @param center
     * @param right
     */
    private static void merge(int[] data, int left, int center, int right) {
        int[] tmpArr = new int[data.length];
        // 右边数组第一个元素的索引
        int mid = center + 1;
        // 记录临时数组的索引
        int third = left;
        // 缓存左边数组的第一个元素的索引
        int tmp = left;
        while (left <= center && mid <= right) {

            if (data[left] < data[mid]) {
                tmpArr[third++] = data[left++];
            } else {
                tmpArr[third++] = data[mid++];
            }

        }
    }
	        // 将剩余部分依次放入临时数组(实际上两个while只会执行其中一个)中
        while (mid <= right) {
            tmpArr[third++] = data[mid++];
        }
        while (left <= center) {
            tmpArr[third++] = data[left++];
        }
        // 将临时数组中的内容复制到原数组中
        while (tmp <= right) {
            data[tmp] = tmpArr[tmp++];
        }

**sout()**每次将数组进行二分拆解,然后对左侧的数组和右侧的数据分别进行递归。
**merge()**先将数组进行冒泡排序,然后依次将冒泡排序的结果放入到临时数组中

7. 桶排序算法

桶排序算法的原理是先找出数组中的最大值和最小值,并根据最大值和最小值定义桶,然后将数据按照大小放入桶中,最后对每个桶进行排序,在每个桶的内部完成排序后,就得到了完整的排序数组

    public static int[] bucketSort(int[] arr) {
        int max = Integer.MAX_VALUE;
        int min = Integer.MIN_VALUE;
        for (int i = 0; i < arr.length; i++) {
            max = Math.max(max, arr[i]);
            min = Math.min(max, arr[i]);
        }

        // 创建桶
        int bucketNum = (max - min) / arr.length + 1;
        ArrayList<ArrayList<Integer>> bucketArr = new ArrayList<>(bucketNum);
        for (int i = 0; i < bucketNum; i++) {
            bucketArr.add(new ArrayList<Integer>());
        }
        // 将每个元素放入桶中
        for (int i = 0; i < arr.length; i++) {
            int num = (arr[i] - min) / (arr.length);
            bucketArr.get(num).add(arr[i]);
        }
        for (int i = 0; i < bucketArr.size(); i++) {
            Collections.sort(bucketArr.get(i));
        }
        return arr;

    }

8. 基数排序算法

基数排序算法是将所有待比较数据统一为同一长度,在位数不够时前面补零,然后从高位根据每个位上整数的大小依次对数据进行排序,最终得到一个有序序列。

9. 其他算法

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值