常见算法汇总

221 阅读3分钟

快速排序-双指针

public class Sort {
    /**
     * 快速排序API
     *
     * @param arr
     */
    public void quickSort(int[] arr) {
        quickSort(arr, 0, arr.length - 1);
    }

    /**
     * 快速排序
     *
     * @param arr   数组
     * @param start 起点
     * @param end   终点
     */
    private void quickSort(int[] arr, int start, int end) {
        //边界
        if (start >= end) {
            return;
        }
        //基准元素下标
        int pivotIdx = partition(arr, start, end);
        //快速排序左半数组,即:数组[start,pivotIdx)
        quickSort(arr, start, pivotIdx - 1);
        //快速排序右半数组,即:数组(pivotIdx,end]
        quickSort(arr, pivotIdx + 1, end);
    }

    /**
     * 划分
     *
     * @param arr   数组
     * @param start 起点
     * @param end   终点
     * @return
     */
    private int partition(int[] arr, int start, int end) {
        //基准
        int pivot = arr[start];
        //左右双指针
        int l = start, r = end;
        while (l != r) {
            //右指针向左移动
            while (l < r && arr[r] > pivot) {
                r--;
            }
            //左指针向右移动
            while (l < r && arr[l] <= pivot) {
                l++;
            }
            if (l < r) {
                swap(arr, l, r);
            }
        }
        //注意:必然有 arr[l]<= arr[start]
        swap(arr, start, l);
        return l;
    }

    /**
     * 交换
     *
     * @param arr 数组
     * @param n   n
     * @param m   m
     */
    private void swap(int[] arr, int n, int m) {
        int tmp = arr[n];
        arr[n] = arr[m];
        arr[m] = tmp;
    }
}

快速排序-单边遍历

public class Sort {
    /**
     * 快速排序API
     *
     * @param arr
     */
    public void quickSort(int[] arr) {
        quickSort(arr, 0, arr.length - 1);
    }

    /**
     * 快速排序
     *
     * @param arr   数组
     * @param start 起点
     * @param end   终点
     */
    private void quickSort(int[] arr, int start, int end) {
        //边界
        if (start >= end) {
            return;
        }
        //基准元素下标
        int pivotIdx = partition(arr, start, end);
        //快速排序左半数组,即:数组[start,pivotIdx)
        quickSort(arr, start, pivotIdx - 1);
        //快速排序右半数组,即:数组(pivotIdx,end]
        quickSort(arr, pivotIdx + 1, end);
    }

    /**
     * 划分
     *
     * @param arr   数组
     * @param start 起点
     * @param end   终点
     * @return
     */
    private int partition(int[] arr, int start, int end) {
        //基准
        int pivot = arr[start];
        //左侧下标
        int idx = start;
        //单边遍历
        for (int i = start + 1; i <= end; i++) {
            if (arr[i] < pivot) {
                idx++;
                swap(arr, i, idx);
            }
        }
        //注意: 必然有 arr[idx] <= arr[start]
        swap(arr, idx, start);
        return idx;
    }

    /**
     * 交换
     *
     * @param arr 数组
     * @param n   n
     * @param m   m
     */
    private void swap(int[] arr, int n, int m) {
        int tmp = arr[n];
        arr[n] = arr[m];
        arr[m] = tmp;
    }
}

冒泡排序

public class Sort {
    public void bobbleSort(int[] arr) {
        int len = arr.length;
        if (len == 0) {
            return;
        }
        //冒泡趟数 k
        for (int k = 0; k < len - 1; k++) {
            //单趟下标 idx
            for (int idx = 0; idx < len - 1 - k; idx++) {
                //交换相邻逆序两数
                if (arr[idx] > arr[idx + 1]) {
                    swap(arr, idx, idx + 1);
                }
            }
        }
    }

    /**
     * 交换
     *
     * @param arr 数组
     * @param n   n
     * @param m   m
     */
    private void swap(int[] arr, int n, int m) {
        int tmp = arr[n];
        arr[n] = arr[m];
        arr[m] = tmp;
    }
}

冒泡排序-优化(避免无交换冒泡趟数)

public class Sort {
    public void bobbleSortAdv(int[] arr) {
        int len = arr.length;
        if (len == 0) {
            return;
        }
        //冒泡趟数 k
        for (int k = 0; k < len - 1; k++) {
            //数组是否有序标记
            boolean isSorted = true;
            //单趟下标 idx
            for (int idx = 0; idx < len - 1 - k; idx++) {
                //交换相邻逆序两数
                if (arr[idx] > arr[idx + 1]) {
                    swap(arr, idx, idx + 1);
                    //本趟交换了则意味着数组任然可能逆序
                    isSorted = false;
                }
            }
            if (isSorted) {
                break;
            }
        }
    }

    /**
     * 交换
     *
     * @param arr 数组
     * @param n   n
     * @param m   m
     */
    private void swap(int[] arr, int n, int m) {
        int tmp = arr[n];
        arr[n] = arr[m];
        arr[m] = tmp;
    }
}

冒泡排序-优化(逐步缩小排序范围)


public class Sort {
    public void bobbleSortAdv(int[] arr) {
        int len = arr.length;
        if (len == 0) {
            return;
        }
        //最后交换位置
        int lastExchangeIdx = 0;
        //排序边界
        int sortBorder = len - 1;
        //冒泡趟数 k
        for (int k = 0; k < len - 1; k++) {
            //数组是否有序标记
            boolean isSorted = true;
            //单趟下标 idx 范围 0至sortBorder
            for (int idx = 0; idx < sortBorder; idx++) {
                //交换相邻逆序两数
                if (arr[idx] > arr[idx + 1]) {
                    swap(arr, idx, idx + 1);
                    //本趟交换了则意味着数组任然可能逆序
                    isSorted = false;
                    //修改最后交换位置
                    lastExchangeIdx = idx;
                }
            }
            //缩小排序边界
            sortBorder = lastExchangeIdx;
            if (isSorted) {
                break;
            }
        }
    }

    /**
     * 交换
     *
     * @param arr 数组
     * @param n   n
     * @param m   m
     */
    private void swap(int[] arr, int n, int m) {
        int tmp = arr[n];
        arr[n] = arr[m];
        arr[m] = tmp;
    }
}

冒泡排序-单链表

public class Sort {
    /**
     * 链表节点
     */
    public static class Node {
        int val;
        Node next;

        Node(int val) {
            this.val = val;
        }
    }

    Node bobbleSort(Node node) {
        if (node == null) {
            return null;
        }
        //冒泡结束标记
        Node tail = null;
        //冒泡趟数控制
        while (tail != node.next) {
            //前一节点 当前节点 后一节点
            Node preNode = null, curNode = node, nextNode = node.next;

            //单趟冒泡
            while (nextNode != tail) {
                if (curNode.val > nextNode.val) {
                    //交换节点
                    curNode.next = nextNode.next;
                    nextNode.next = curNode;
                    if (preNode == null) {
                        //修改首节点指针
                        node = nextNode;
                    } else {
                        preNode.next = nextNode;
                    }

                    //移动指针
                    preNode = nextNode;
                    nextNode = curNode.next;
                    continue;
                }

                //移动指针
                preNode = curNode;
                curNode = nextNode;
                nextNode = nextNode.next;
            }

            //修改本趟冒泡尾标记
            tail = curNode;
        }
        return node;
    }
}

冒泡排序-鸡尾酒排序

public class Sort {
    /**
     * 鸡尾酒排序-冒泡排序变体
     *
     * @param arr
     */
    public void cockTailSort(int[] arr) {
        int len = arr.length;
        if (len == 0) {
            return;
        }
        //趟数 k
        for (int k = 0; k < len / 2; k++) {
            //有序标记
            boolean isSorted = true;
            for (int idx = k; idx < len - 1 - k; idx++) {
                if (arr[idx] > arr[idx + 1]) {
                    swap(arr, idx, idx + 1);
                    isSorted = false;
                }
            }
            //判断是否已经有序
            if (isSorted) {
                break;
            }
            isSorted = true;
            for (int idx = len - 1 - k; idx > k; idx--) {
                if (arr[idx] < arr[idx - 1]) {
                    swap(arr, idx, idx - 1);
                    isSorted = false;
                }
            }
            //判断是否已经有序
            if (isSorted) {
                break;
            }
        }
    }

    /**
     * 交换
     *
     * @param arr 数组
     * @param n   n
     * @param m   m
     */
    private void swap(int[] arr, int n, int m) {
        int tmp = arr[n];
        arr[n] = arr[m];
        arr[m] = tmp;
    }
}

冒泡排序-鸡尾酒排序优化(逐步缩小排序范围)

public class Sort {
    /**
     * 鸡尾酒排序-冒泡排序变体
     *
     * @param arr
     */
    public void cockTailSortAdv(int[] arr) {
        int len = arr.length;
        if (len == 0) {
            return;
        }
        int leftExchange = -1, rightExchange = -1;
        //排序左右边界
        int leftSortBorder = 0, rightSortBorder = len - 1;
        //趟数 k
        for (int k = 0; k < len / 2; k++) {
            //有序标记
            boolean isSorted = true;
            for (int idx = leftSortBorder; idx < rightSortBorder; idx++) {
                if (arr[idx] > arr[idx + 1]) {
                    swap(arr, idx, idx + 1);
                    isSorted = false;
                    rightExchange = idx;
                }
            }
            //判断是否已经有序
            if (isSorted) {
                break;
            }
            rightSortBorder = rightExchange;


            isSorted = true;
            for (int idx = rightSortBorder; idx > leftSortBorder; idx--) {
                if (arr[idx] < arr[idx - 1]) {
                    swap(arr, idx, idx - 1);
                    isSorted = false;
                    leftExchange = idx;
                }
            }
            //判断是否已经有序
            if (isSorted) {
                break;
            }
            leftSortBorder = leftExchange;
        }

    }

    /**
     * 交换
     *
     * @param arr 数组
     * @param n   n
     * @param m   m
     */
    private void swap(int[] arr, int n, int m) {
        int tmp = arr[n];
        arr[n] = arr[m];
        arr[m] = tmp;
    }
}

计数排序

public class Sort {
    public int[] countSort(int[] arr) {
        int len = arr.length;
        if (len == 0) {
            return new int[0];
        }
        //数列最大、最小值
        int max = arr[0], min = arr[0];
        for (int idx = 1; idx < len; idx++) {
            if (max < arr[idx]) {
                max = arr[idx];
            }
            if (min > arr[idx]) {
                min = arr[idx];
            }
        }

        //计数表
        int[] cnt = new int[max - min + 1];
        for (int idx = 0; idx < len; idx++) {
            cnt[arr[idx] - min]++;
        }
        //计数表 -> 顺位表
        for (int idx = 1; idx < cnt.length; idx++) {
            cnt[idx] += cnt[idx - 1];
        }

        //逆序遍历原数组(保证相同数值的两数顺位)
        int[] res = new int[len];
        for (int idx = len - 1; idx >= 0; idx--) {
            res[cnt[arr[idx] - min] - 1] = arr[idx];
            cnt[arr[idx] - min]--;
        }
        return res;

    }
}

桶排序

public class Sort {
    public double[] bucketSort(double[] arr) {
        int len = arr.length;
        if (len == 0) {
            return new double[0];
        }
        //最大最小值
        double max = arr[0], min = arr[0];
        for (int idx = 1; idx < len; idx++) {
            if (min > arr[idx]) {
                min = arr[idx];
            }
            if (max < arr[idx]) {
                max = arr[idx];
            }
        }

        //桶 桶的数目等于数组长度,则最悲观情况下一个桶一个元素
        List<LinkedList<Double>> bucket = new ArrayList<>(len);
        for (int idx = 0; idx < len; idx++) {
            bucket.add(new LinkedList<>());
        }

        //元素置入桶中
        for (int idx = 0; idx < len; idx++) {
            //桶编号
            int num = (int) ((arr[idx] - min) * (len-1) / (max - min));
            bucket.get(num).add(arr[idx]);
        }
        //桶内排序
        for (int idx = 0; idx < len; idx++) {
            Collections.sort(bucket.get(idx));
        }

        //构建结果集
        double[] res = new double[len];
        int idx = 0;
        for (LinkedList<Double> l : bucket) {
            for (double e : l) {
                res[idx++] = e;
            }
        }

        return res;
    }
}

未完待续...