整理几个比较好的算法(一)

以下资料均来自 bilibili的韩顺平老师

1.排序算法

①希尔排序

基本思想:希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含 的关键词越来越多, 当增量减至 1 时,整个文件恰被分成一组,算法便终止
package sort;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
/**
 * @Author hecheng
 * @Date 2020/6/25 21:29
 * @Version 1.0
 *
 * 希尔排序
 */
public class ShellSort {
    public static void main(String[] args) {
        int[] arr = new int[]{ 8, 9, 1, 7, 2, 3, 5, 4, 6, 0};

        sheelSort2(arr);
        System.out.println(Arrays.toString(arr));
        ///速度测试  8w 1s不到 80w 1秒 
        /*int[] arr1 = new int[80000];
        //随机生成80000个数
        for (int i=0;i<80000;i++){
            arr1[i] = (int) (Math.random() * 800000);
        }

        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String s = simpleDateFormat.format(date);
        System.out.println("转换前的时间为:"+s);

        sheelSort2(arr1);

        Date date1 = new Date();
        String s1 = simpleDateFormat.format(date1);
        System.out.println("转换后的时间为:"+s1);*/
        ///速度测试
    }

    public static void sheelSort(int[] arr) {
        int len = arr.length;
        int temp = 0;
        for (int gap = len / 2; gap > 0; gap /= 2) { //比如10个数  变为 5 2 1

            for (int i = gap; i < len; i++) {    //代表多少组 比如gap=5时,表示有5组,2的时候2组

                for (int j = i - gap; j >= 0; j -= gap) { //每一组进行插入排序  (这一步明天继续理解下)
                    if (arr[j] > arr[gap + j]) {
                        temp = arr[j];
                        arr[j] = arr[gap + j];
                        arr[gap + j] = temp;
                    }
                }
            }
        }
    }
    /**
     * 希尔排序
     * 优化
     * @param arr
     */
    public static void sheelSort2(int[] arr) {
        int len = arr.length;
        for (int gap = len / 2; gap > 0; gap /= 2) {

            for (int i = gap; i < len; i++) {
                int j = i;
                int temp = arr[j];
                while (j - gap >= 0 && temp < arr[j - gap]) {
                    //移动
                    arr[j] = arr[j-gap];
                    j -= gap;
                }
                //当退出 while 后,就给 temp 找到插入的位置
                arr[j] = temp;
            }
        }
    }
}

②快速排序

基本思想是:通过一趟排序将要排序的数据分割成独立的两 部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排 序, 整个排序过程可以递归进行,以此达到整个数据变成有序序列
package sort;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

/**
 * @Author hecheng
 * @Date 2020/6/26 9:59
 * @Version 1.0
 * 快速排序
 */
public class QuickSort {
    public static void main(String[] args) {
        /*int[] arr = new int[]{8, 9, 1, 7, 2, 3, 5, 4, 6, 0};
        quickSort(arr, 0, arr.length - 1);
        System.out.println(Arrays.toString(arr));*/
        ///速度测试 800w 1秒 8000w 11秒
        int[] arr1 = new int[8000000];
        //随机生成80000个数
        for (int i=0;i<8000000;i++){
            arr1[i] = (int) (Math.random() * 80000000);
        }

        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String s = simpleDateFormat.format(date);
        System.out.println("转换前的时间为:"+s);

        quickSort(arr1, 0, arr1.length - 1);

        Date date1 = new Date();
        String s1 = simpleDateFormat.format(date1);
        System.out.println("转换后的时间为:"+s1);

//        System.out.println(Arrays.toString(arr1));
        ///速度测试
    }
    /**
     * @param arr
     * @param left
     * @param right
     * x=8
     * 8, 9, 1, 7, 2, 3, 5, 4, 6, 0
     * ② 0, 9, 1, 7, 2, 3, 5, 4, 6, 8  r=9
     * ④ 0, 9, 1, 7, 2, 3, 5, 4, 6, 9  l=1,r=8
     * ...
     * 0, 6, 1, 7, 2, 3, 5, 4, 6, 9  r=8,l=8
     *
     */
    public static void quickSort(int[] arr, int left, int right) {
        if (left < right) {
            int l = left, r = right, x = arr[left];

            while (l < r) {
                //①
                while (l < r && arr[r] >= x) {    //找出右边的小于x的数
                    r--;
                }
                //②
                if (l < r) {
                    arr[l++] = arr[r];            //将刚找到的右边的小于x的数放入左边最前面, 所以l++是将左边要移动的位置 +1
                }
                //③
                while (l < r && arr[l] < x) {     //找出左边的大于x的数
                    l++;
                }
                //④
                if (l < r) {
                    arr[r--] = arr[l];            //给刚才右边换过来的位置赋上左边选出来的数
                }
            }
            arr[l] = x;
            quickSort(arr, left, l - 1);
            quickSort(arr, l + 1, right);
        }
    }
}

查找算法

①斐波那契(黄金分割法)查找算法
1) 黄金分割点是指把一条线段分割为两部分,使其中一部分与全长之比等于另一部分与这部分之比。取其前三位 数字的近似值是 0.618。由于按此比例设计的造型十分美丽,因此称为黄金分割,也称为中外比。这是一个神 奇的数字,会带来意向不大的效果。
2) 斐波那契数列 {1, 1, 2, 3, 5, 8, 13, 21, 34, 55 } 发现斐波那契数列的两个相邻数 的比例,无限接近 黄金分割值 0.618
斐波那契(黄金分割法)原理:

在这里插入图片描述
在这里插入图片描述

package search;

import java.util.Arrays;

/**
 * @Author hecheng
 * @Date 2020/6/27 15:26
 * @Version 1.0
 */
public class FibonacciSearch {
    public static int maxSize = 20;

    public static void main(String[] args) {
        int[] arr = {1, 8, 10, 89, 1000, 1234};
        System.out.println("index=" + fibSearch(arr, 10));// 0
    }

    //因为后面我们 mid=low+F(k-1)-1,需要使用到斐波那契数列,因此我们需要先获取到一个斐波那契数列
    //非递归方法得到一个斐波那契数列
    public static int[] fib() {
        int[] f = new int[maxSize];
        f[0] = 1;
        f[1] = 1;
        for (int i = 2; i < maxSize; i++) {
            f[i] = f[i - 1] + f[i - 2];
        }
        return f;
    }

    //编写斐波那契查找算法
    //使用非递归的方式编写算法
    /**
     * @param a   数组
     * @param key 我们需要查找的关键码(值)
     * @return 返回对应的下标,如果没有-1
     */
    public static int fibSearch(int[] a, int key) {
        int low = 0;
        int high = a.length - 1;
        int k = 0; //表示斐波那契分割数值的下标
        int mid = 0; //存放 mid 值
        int f[] = fib(); //获取到斐波那契数列
        //获取到斐波那契分割数值的下标
        while (high > f[k] - 1) {
            k++;
        }
        //因为 f[k] 值 可能大于 a 的 长度,因此我们需要使用 Arrays 类,构造一个新的数组,并指向 temp[]
        //不足的部分会使用 0 填充
        int[] temp = Arrays.copyOf(a, f[k]);
        //实际上需求使用 a 数组最后的数填充 temp
        //举例:
        //temp = {1,8, 10, 89, 1000, 1234, 0, 0} => {1,8, 10, 89, 1000, 1234, 1234, 1234,}
        for (int i = high + 1; i < temp.length; i++) {
            temp[i] = a[high];
        }
        // 使用 while 来循环处理,找到我们的数 key
        while (low <= high) { // 只要这个条件满足,就可以找
            mid = low + f[k - 1] - 1;
            if (key < temp[mid]) { //我们应该继续向数组的前面查找(左边)
                high = mid - 1;
                //为甚是 k--
                //说明
                //1. 全部元素 = 前面的元素 + 后边元素
                //2. f[k] = f[k-1] + f[k-2]
                //因为 前面有 f[k-1]个元素,所以可以继续拆分 f[k-1] = f[k-2] + f[k-3]
                                //即 在 f[k-1] 的前面继续查找 k--
                //即下次循环 mid = f[k-1-1]-1
                k--;
            } else if (key > temp[mid]) { // 我们应该继续向数组的后面查找(右边)
                low = mid + 1;
                //为什么是 k -=2
                //说明
                //1. 全部元素 = 前面的元素 + 后边元素
                //2. f[k] = f[k-1] + f[k-2]
                //3. 因为后面我们有 f[k-2] 所以可以继续拆分 f[k-1] = f[k-3] + f[k-4]
                //4. 即在 f[k-2] 的前面进行查找 k -=2
                //5. 即下次循环 mid = f[k - 1 - 2] - 1
                k -= 2;
            } else { //找到
                //需要确定,返回的是哪个下标
                if (mid <= high) {
                    return mid;
                } else {        //mid超过原数组的下标,则返回high
                    return high;
                }
            }
        }
        return -1;
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值