算法总结代码实现

一、排序查找算法

1、选择排序

1)原理:

  (selectSort)遍历元素找到一个最小(或最大)的元素,把它放在第一个位置,然后再在剩余元素中找到最小(或最大)的元素,把它放在第二个位置,依次下去,完成排序。

 2)直接选择排序步骤:

 

 

 n个记录的文件的直接选择排序可经过n-1趟直接选择排序得到有序结果:
      ①初始状态:无序区为R[1..n],有序区为空。
      ②第1趟排序
           在无序区R[1..n]中选出关键字最小的记录R[k],将它与无序区的第1个记录R[1]交换,使R[1..1]和R[2..n]分别变为记录个数增加1个的新有序
        区和记录个数减少1个的新无序区。
      ……
      ③第i趟排序
          第i趟排序开始时,当前有序区和无序区分别为R[1..i-1]和R[i..n](1≤i≤n-1)。该趟排序从当前无序区中选出关键字最小的记录R[k],将它与无
        序区的第1个记录R[i]交换,使R[1..i]和R[i+1..n]分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区。这样,n个记录的文件的直接
        选择排序可经过n-1趟直接选择排序得到有序结果。

3)算法分析: (1)关键字比较次数

   无论文件初始状态如何,在第i趟排序中选出最小(或者最大值)关键字的记录,需做n-i次比较,因此,总的比较次数为: n(n-1)/2=o(n^2)

(2)记录的移动次数

    当初始文件为正序时,移动次数为0
    无论文件初始状态如何,在第i趟排序中选出最小(或者最大值)关键字的记录,需做n-i次比较,因此,总的比较次数为: n(n-1)/2=o(n^2)

(3)直接选择排序是一个就地排序 (4)稳定性分析  直接选择排序是稳定的

4)Java实现

排序算法抽象类,后排排序均实现AbstractSort类

package com.wei.arithmetic.base.sort;

public interface Sort<T> {

    /**
     * 排序int数组
     *
     * @param array 排序数组
     * @param order -1 降序,其余升序
     */
    int[] sort(int[] array, int order);

    /**
     * 排序对象数组
     *不支持数组中含有null元素,null元素会抛出空指针
     * @param array 排序数组
     * @param order -1 降序,其余升序
     */
    T[] sort(T[] array, int order);

}

package com.wei.arithmetic.base.sort.abs;
import com.wei.arithmetic.base.sort.Sort;
import java.util.Comparator;

public abstract class AbstractSort<T> implements Sort<T> {

    protected final Comparator<T> comparator;

    protected AbstractSort(Comparator<T> comparator) {
        this.comparator = comparator;
    }

    protected AbstractSort() {
        this.comparator = null;
    }

    protected void swap(int[] arr, int i, int j) {
        if (arr == null || arr.length == 0 || i == j) {
            return;
        }
        arr[i] = arr[i] ^ arr[j];
        arr[j] = arr[i] ^ arr[j];
        arr[i] = arr[i] ^ arr[j];
    }

    protected <T> void swap(T[] arr, int i, int j) {
        if (arr == null || arr.length == 0 || i == j) {
            return;
        }
        T temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

}

排序测试类

package com.wei.arithmetic.test;

import com.alibaba.fastjson.JSON;
import com.wei.arithmetic.base.MergeSort;
import com.wei.arithmetic.base.ShellSort;
import com.wei.arithmetic.base.sort.Sort;
import com.wei.utils.ArithmeticUtils;

import java.util.Comparator;

public class SortTest {
    public static void main(String[] args) {
        Integer[] array1 = ArithmeticUtils.getRandomIntegerArray(20, 1, 1000);
        int[] array2 = ArithmeticUtils.getRandomIntArrays(11, 1, 1000);
        System.out.println(JSON.toJSON(array2));
        //测试选择排序
        Sort sort;
        long start = System.currentTimeMillis();
        //1.选择排序
        //sort = new SelectSort(Comparator.comparingInt(o -> (int) o));

        //2.冒泡排序
        //sort = new BubbleSort(Comparator.comparingInt(o -> (int) o));

        //3.插入排序
        //sort = new InsertSort(Comparator.comparingInt(o -> (int) o));

        //4.快速排序
        //sort = new QuickSort(Comparator.comparingInt(o -> (int) o));

        //5.归并排序
        //sort = new MergeSort(Comparator.comparingInt(o -> (int) o));

        //6.希尔排序
        sort = new ShellSort(Comparator.comparingInt(o -> (int) o));
        sort.sort(array2, 1);

        //7.桶排序
        long end = System.currentTimeMillis();
        //用于比较各种算法花费时间长短
        System.out.println("-------waste time:" + (end - start));
        System.out.println(JSON.toJSON(array2));
    }


}

package com.wei.arithmetic.base;

import com.alibaba.fastjson.JSON;
import com.wei.arithmetic.base.sort.abs.AbstractSort;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.util.Comparator;
public class SelectSort<T> extends AbstractSort<T> {

    private static Logger log = LoggerFactory.getLogger(SelectSort.class);

    public SelectSort(Comparator<T> comparator) {
        super(comparator);
    }

    public SelectSort() {
    }
    
    @Override
    public int[] sort(int[] array, int order) {
        if (array == null || array.length == 0) {
            return array;
        }
        //比较次数
        int count = 0;
        int length = array.length - 1;
        //需要比较的次数为array.length - 1次
        for (int i = 0; i < length; i++) {
            //假设每一趟第一个元素都是最小值或者最大值,记录当前索引
            int temp = i;
            //从剩余未排序序列中找到最小值下标
            for (int j = i + 1; j < array.length; j++) {
                count++;
                //降序排序
                if (order == -1) {
                    if (array[temp] < array[j]) {
                        temp = j;
                    }
                } else {//升序排序
                    if (array[temp] > array[j]) {
                        temp = j;
                    }
                }
                log.debug("比较次数为:{}, array:{}", count, JSON.toJSON(array));
            }
            //如果本身就是最小值或者最大值下标,则不需要交换
            if (temp != i) {
                swap(array, i, temp);
            }
        }
        return array;
    }

    @Override
    public T[] sort(T[] array, int order) {
        if (array == null || array.length == 0) {
            return array;
        }
        //存放每次最大或者最小值的数组下标
        int temp;
        //比较次数
        int count = 0;
        for (int i = 0; i < array.length - 1; i++) {
            temp = i;
            for (int j = i + 1; j < array.length; j++) {
                count++;
                //降序排序
                boolean bl = (comparator != null && comparator.compare(array[temp], 						array[j]) < 0)
                        || ((Comparable & Serializable) array[temp]).compareTo(array[j]) 					< 0;
                if (order > 0) {
                    if (bl) {
                        temp = j;
                    }
                } else {
                    //升序排序
                    if (!bl) {
                        temp = j;
                    }
                }
                log.debug("比较次数为:{}, array:{}", count, JSON.toJSON(array));
            }
            if (temp != i) {
                swap(array, i, temp);
            }
        }
        return array;
    }
}

5)应用

2、冒泡排序

1)原理:

(bubbleSort)依次比较相邻的两个数,将小/大数放在前面,大/小数数放在后面。

 

 2)比较步骤:

 设数组的长度为N:
  (1)比较前后相邻的二个数据,如果前面数据大于后面的数据,就将这二个数据交换。
  (2)这样对数组的第0个数据到N-1个数据进行一次遍历后,最大的一个数据就“沉”到数组第N-1个位置。
  (3)N=N-1,如果N不为0就重复前面二步,否则排序完成。

3)算法分析: (1)关键字比较次数

  如果我们的数据正序,只需要走一趟即可完成排序。所需的比较次数C和记录移动次数M均达到最小值,即:Cmin=n-1;Mmin=0;所以,冒泡排序最好的时间复杂度为O(n)。
  如果很不幸我们的数据是反序的,则需要进行n-1趟排序。每趟排序要进行n-i次比较(1≤i≤n-1),且每次比较都必须移动记录三次来达到交换记录位置。在这种情况下,比较和移动次数均达到最大值,冒泡排序总的平均时间复杂度为:

(2)稳定性分析  稳定的

4)Java实现

 package com.wei.arithmetic.base;

import com.wei.arithmetic.base.sort.abs.AbstractSort;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.util.Comparator;

public class BubbleSort<T> extends AbstractSort<T> {

    private static Logger log = LoggerFactory.getLogger(BubbleSort.class);

    public BubbleSort(Comparator<T> comparator) {
        super(comparator);
    }

    public BubbleSort() {
    }

    /**
     * @param array 排序数组
     * @param order -1 降序,其余升序
     */
    @Override
    public int[] sort(int[] array, int order) {
        if (array == null || array.length == 0) {
            return array;
        }
        boolean isSwap;
        int count = 0;
        for (int i = 0; i < array.length; i++) {
            isSwap = false;
            for (int j = 0; j < array.length - i - 1; j++) {
                count++;
                //降序排序
                if (order == -1) {
                    if (array[j] - array[j + 1] < 0) {
                        isSwap = true;
                        swap(array, j, j + 1);
                    }
                } else {
                    //升序排序
                    if (array[j] - array[j + 1] > 0) {
                        isSwap = true;
                        swap(array, j, j + 1);
                    }
                }
                //log.info("第 {} 次排序后array:{}", count, JSON.toJSON(array));
            }
            //未交换位置,说明已经是有序数组
            if (!isSwap) {
                break;
            }
        }
        return array;
    }


    @Override
    public T[] sort(T[] array, int order) {
        if (array == null || array.length == 0) {
            return array;
        }
        boolean isSwap;
        int count = 0;
        for (int i = 0; i < array.length; i++) {
            isSwap = false;
            for (int j = 0; j < array.length - i - 1; j++) {
                count++;
                boolean bl = (comparator != null && comparator.compare(array[j], 								array[j]) < 0)
                        || ((Comparable & Serializable) array[j]).compareTo(array[j + 1]) 							< 0;
                //降序排序
                if (order == -1) {
                    if (bl) {
                        isSwap = true;
                        swap(array, j, j + 1);
                    }
                } else {
                    //升序排序
                    if (!bl) {
                        isSwap = true;
                        swap(array, j, j + 1);
                    }
                }
                //log.info("第 {} 次排序后array:{}", count, JSON.toJSON(array));
            }
            //未交换位置,说明已经是有序数组
            if (!isSwap) {
                break;
            }
        }
        return array;
    }
}

5)应用

3、插入排序

1)原理:

   (insertSort)利用插入法对无序数组排序时,我们其实是将数组R划分成两个子区间R[1..i-1](已排好序的有序区)和R[i..n](当前未排序的部分,
   可称无序区)。插入排序的基本操作是将当前无序区的第1个记录R[i]插人到有序区R[1..i-1]中适当的位置上,使R[1..i]变为新的有序区。因为
这种方法每次使有序区增加1个记录,通常称增量法。

 

 2)步骤:

1、以数组的某一位作为分隔位,比如index=1,假设左面的都是有序的
 2、将index位的数据拿出来,放到临时变量里,这时index位置就空出来了.
 3、从leftindex=index-1开始将左面的数据与当前index位的数据(即temp)进行比较,如果array[leftindex]>temp,
 则将array[leftindex]后移一位,即array[leftindex+1]=array[leftindex],此时leftindex就空出来了
 4、再用index-2(即leftindex=leftindex-1)位的数据和temp比,重复步骤3,
    直到找到<=temp的数据或者比到了最左面(说明temp最小),停止比较,将temp放在当前空的位置上
 5、index向后挪1,即index=index+1,temp=array[index],重复步骤2-4,直到index=array.length,排序结束,
    此时数组中的数据即为从小到大的顺序.
3)算法分析:
稳定 
空间复杂度O(1) 
时间复杂度O(n2) 
最差情况:反序,需要移动n*(n-1)/2个元素 
最好情况:正序,不需要移动元素

3)算法分析:

(1)稳定性分析  稳定的

4)Java实现

package com.wei.arithmetic.base;

import com.alibaba.fastjson.JSON;
import com.wei.arithmetic.base.sort.Sort;
import com.wei.arithmetic.base.sort.abs.AbstractSort;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.util.Comparator;

public class InsertSort<T> extends AbstractSort<T> {

    private static Logger log = LoggerFactory.getLogger(InsertSort.class);

    public InsertSort() {

    }
    public InsertSort(Comparator<T> comparator) {
        super(comparator);
    }

    /**
     * 插入排序
     *
     * @param array 排序数组
     * @param order -1 降序,其余升序
     */
    @Override
    public int[] sort(int[] array, int order) {
        if (array == null || array.length == 0) {
            return array;
        }
        //比较的次数
        int count = 0;
        //记录需要插入的值
        int indexValue;
        for (int i = 0; i < array.length - 1; i++) {
            int index = i + 1;
            indexValue = array[index];
            for (int j = i; j >= 0; j--) {
                count++;
                //降序排序
                if (order == -1) {
                    if (array[j] < indexValue) {
                        //后移一位
                        array[j + 1] = array[j];
                        //记录下后移完成后,空缺后需要填充的位置
                        index = j;
                    }
                } else {//升序排序
                    if (array[j] > indexValue) {
                        //后移一位
                        array[j + 1] = array[j];
                        //记录下后移完成后,空缺后需要填充的位置
                        index = j;
                    }
                }
                log.debug("第{}次比较,array:{}", count, JSON.toJSON(array));
            }
            //将临时变量保存的临时值插入
            array[index] = indexValue;
        }
        return array;
    }

    @Override
    public T[] sort(T[] array, int order) {
        if (array == null || array.length == 0) {
            return array;
        }
        int index;
        T temp;
        int count = 0;
        for (int i = 0; i < array.length - 1; i++) {
            index = i + 1;
            temp = array[index];
            for (int j = i; j >= 0; j--) {
                count++;
                boolean isChange = (comparator != null && comparator.compare(array[j], 								temp) < 0)
                        || (((Comparable<T> & Serializable) array[j]).compareTo(temp) < 							0);
                if (order == -1) {
                    if (isChange) {
                        array[j + 1] = array[j];
                        index = j;
                    }
                } else {
                    if (!isChange) {
                        array[j + 1] = array[j];
                        index = j;
                    }
                }
                log.debug("第{}次比较,array:{}", count, JSON.toJSON(array));
            }
            array[index] = temp;
        }
        return array;
    }

}

5)应用

4、快速排序

1)原理:

   (QuickSort)选择一个关键值作为基准值。比基准值小的都在左边序列(无序的),比基准值大的都在右边(无序的)。 一般选择序列的第一个元素

 

 2)步骤:

 设要排序的数组是A[0]……A[N-1]
 1、设置两个变量I、J,排序开始的时候:I=0,J=N-1; 
 2、以第一个数组元素作为关键数据,赋值给X,即 X=A[0]; 
 3、从J开始向前搜索,即由后开始向前搜索(J=J-1),找到第一个小于X的值,让该值与X交换; 
 4、从I开始向后搜索,即由前开始向后搜索(I=I+1),找到第一个大于X的值,让该值与X交换; 
 5、重复第3、4步,直到 I=J;

3)算法分析: 稳定 空间复杂度O(1) 时间复杂度O(nlogn) 最差情况:反序,需要移动n*(n-1)/2个元素 最好情况:正序,不需要移动元素

4)Java实现

package com.wei.arithmetic.base;

import com.wei.arithmetic.base.sort.abs.AbstractSort;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.util.Comparator;

public class QuickSort<T> extends AbstractSort<T> {

    private static final Logger log = LoggerFactory.getLogger(QuickSort.class);


    public QuickSort(Comparator<T> comparator) {
        super(comparator);
    }

    public QuickSort() {
    }

    /**
     * @param array 排序数组
     * @param order -1 降序,其余升序
     * @return
     */
    @Override
    public int[] sort(int[] array, int order) {
        if (array == null || array.length <= 1) {
            return array;
        }
        quickSort(array, 0, array.length - 1, order);
        return array;
    }

    private void quickSort(int[] array, int left, int right, int order) {
        if (array.length <= 1 || left >= right) {
            return;
        }
        int mid = partition(array, left, right, order);
        quickSort(array, left, mid, order);
        quickSort(array, mid + 1, right, order);
        //log.info("array:{}", JSON.toJSON(array));
    }

    private int partition(int[] array, int left, int right, int order) {
        int temp = array[left];
        boolean desc = (order == -1);
        while (left < right) {
            if (desc) {
                // 先从最右边依次和基数做比较
                while (left < right && temp >= array[right]) {
                    right--;
                }
                // 当基准数小于了 arr[right],则填坑
                if (left < right) {
                    array[left] = array[right];
                    left++;
                }
                //在从左边依次和基数做比较
                while (left < right && temp <= array[left]) {
                    left++;
                }
                // 当基准数大于了 arr[left],则填坑
                if (left < right) {
                    array[right] = array[left];
                    right--;
                }
            } else {
                // 先从最右边依次和基数做比较
                while (left < right && temp <= array[right]) {
                    right--;
                }
                // 当基准数大于了 arr[right],则填坑
                if (left < right) {
                    array[left] = array[right];
                    left++;
                }
                //在从左边依次和基数做比较
                while (left < right && temp >= array[left]) {
                    left++;
                }
                // 当基准数大于了 arr[left],则填坑
                if (left < right) {
                    array[right] = array[left];
                    right--;
                }
            }
        }
        array[left] = temp;
        return left;
    }

    @Override
    public T[] sort(T[] array, int order) {
        if (array == null || array.length <= 1) {
            return array;
        }
        quickSort(array, 0, array.length - 1, order);
        return array;
    }

    private void quickSort(T[] array, int left, int right, int order){
        if (array.length <= 1 || left >= right) {
            return;
        }
        int mid = partition(array, left, right, order);
        quickSort(array, left, mid, order);
        quickSort(array, mid + 1, right, order);
        //log.info("array:{}", JSON.toJSON(array));
    }

    private int partition(T[] array, int left, int right, int order) {
        T temp = array[left];
        boolean desc = (order == -1);
        while (left < right) {
            if (desc) {
                // 先从最右边依次和基数做比较
                while (left < right && ((comparator != null && comparator.compare(temp, 							array[right]) >= 0) ||
                        ((Comparable<T> & Serializable)temp).compareTo(array[right]) >= 							0)) {
                    right--;
                }
                // 当基准数小于了 arr[right],则填坑
                if (left < right) {
                    array[left] = array[right];
                    left++;
                }
                //在从左边依次和基数做比较
                while (left < right && ((comparator != null && comparator.compare(temp, 							array[left]) <= 0) ||
                        ((Comparable<T> & Serializable)temp).compareTo(array[left]) <= 								0)) {
                    left++;
                }
                // 当基准数大于了 arr[left],则填坑
                if (left < right) {
                    array[right] = array[left];
                    right--;
                }
            } else {
                // 先从最右边依次和基数做比较
                while (left < right && ((comparator != null && comparator.compare(temp, 							array[right]) <= 0) ||
                        ((Comparable<T> & Serializable)temp).compareTo(array[right]) <= 							0)) {
                    right--;
                }
                // 当基准数大于了 arr[right],则填坑
                if (left < right) {
                    array[left] = array[right];
                    left++;
                }
                //在从左边依次和基数做比较
                while (left < right && ((comparator != null && comparator.compare(temp, 							array[left]) >= 0) ||
                        ((Comparable<T> & Serializable)temp).compareTo(array[left]) >= 								0)) {
                    left++;
                }
                // 当基准数大于了 arr[left],则填坑
                if (left < right) {
                    array[right] = array[left];
                    right--;
                }
            }
        }
        array[left] = temp;
        return left;
    }
}

5)应用

5、归并排序

1)原理:

 归并排序(Merge Sort)就是利用归并思想对数列进行排序。根据具体的实现,归并排序包括"从上往下"和"从下往上"2种方式

2)步骤:

 1. 从下往上的归并排序:将待排序的数列分成若干个长度为1的子数列,然后将这些数列两两合并;得到若干个长度为2的有序数列,再将这些数列两两合并;得到若干个长度为4的有序数列,再将它们两两合并;直接合并成一个数列为止。这样就得到了我们想要的排序结果。

2. 从上往下的归并排序:它与"从下往上"在排序上是反方向的。它基本包括3步:
① 分解 -- 将当前区间一分为二,即求分裂点 mid = (low + high)/2;
② 求解 -- 递归地对两个子区间a[low...mid] 和 a[mid+1...high]进行归并排序。递归的终结条件是子区间长度为1。
③ 合并 -- 将已排序的两个子区间a[low...mid]和 a[mid+1...high]归并为一个有序的区间a[low...high]。

 

3)算法分析: (1)稳定性  归并排序是一种稳定的排序。 (2)存储结构要求  可用顺序存储结构。也易于在链表上实现。 (3)时间复杂度  对长度为n的文件,需进行趟二路归并,每趟归并的时间为O(n),故其时间复杂度无论是在最好情况下还是在最坏情况下均是O(nlgn)。 (4)空间复杂度 需要一个辅助向量来暂存两有序子文件归并的结果,故其辅助空间复杂度为O(n),显然它不是就地排序。 注意:  若用单链表做存储结构,很容易给出就地的归并排序

4)Java实现

package com.wei.arithmetic.base;

import com.wei.arithmetic.base.sort.abs.AbstractSort;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.util.Comparator;

public class MergeSort<T> extends AbstractSort<T> {
    private static final Logger log = LoggerFactory.getLogger(MergeSort.class);

    public MergeSort(Comparator<T> comparator) {
        super(comparator);
    }
    public MergeSort() {
    }


    /**
     * @param array 排序数组
     * @param order -1 降序,其余升序
     * @return
     */
    @Override
    public int[] sort(int[] array, int order) {
        if (array == null || array.length <= 1) {
            return array;
        }
        mergeSort(array, 0, array.length - 1, order);
        return array;
    }

    private void mergeSort(int[] array, int left, int right, int order) {
        if (left >= right) {
            return;
        }
        int mid = (left + right) >> 1;
        mergeSort(array, left, mid, order);
        mergeSort(array, mid + 1, right, order);
        merge(array, left, mid, right, order);
        //log.info("array:{}", JSON.toJSON(array));
    }

    private  void merge(int[] array, int left, int mid, int right, int order) {
        int[] temp = new int[right - left + 1];
        int i = left;
        int j = mid + 1;
        int k = 0;
        while (i <= mid && j <= right) {
            //降序排序
            if (order == -1) {
                if (array[i] > array[j]) {
                    temp[k++] = array[i++];
                } else {
                    temp[k++] = array[j++];
                }
            } else {
                if (array[i] < array[j]) {
                    temp[k++] = array[i++];
                } else {
                    temp[k++] = array[j++];
                }
            }
        }
        //
        while (i <= mid) {
            temp[k++] = array[i++];
        }
        while (j <= right) {
            temp[k++] = array[j++];
        }
        System.arraycopy(temp, 0, array, left, temp.length);
        temp = null;
    }

    @Override
    public T[] sort(T[] array, int order) {
        if (array == null || array.length <= 1) {
            return array;
        }
        mergeSort(array, 0, array.length - 1, order);
        return array;
    }

    private void mergeSort(T[] array, int left, int right, int order) {
        if (left >= right) {
            return;
        }
        int mid = (left + right) >> 1;
        mergeSort(array, left, mid, order);
        mergeSort(array, mid + 1, right, order);
        merge(array, left, mid, right, order);
        //log.info("array:{}", JSON.toJSON(array));
    }

    private  void merge(T[] array, int left, int mid, int right, int order) {
        Object[] temp = new Object[right - left + 1];
        int i = left;
        int j = mid + 1;
        int k = 0;
        while (i <= mid && j <= right) {
            boolean bl = (comparator != null && comparator.compare(array[i], array[j]) > 						0)
                    || (((Comparable<T> & Serializable)array[i]).compareTo(array[j]) > 						   0);
            //降序排序
            if (order == -1) {
                if (bl) {
                    temp[k++] = array[i++];
                } else {
                    temp[k++] = array[j++];
                }
            } else {
                if (!bl) {
                    temp[k++] = array[i++];
                } else {
                    temp[k++] = array[j++];
                }
            }
        }
        //
        while (i <= mid) {
            temp[k++] = array[i++];
        }
        while (j <= right) {
            temp[k++] = array[j++];
        }
        System.arraycopy(temp, 0, array, left, temp.length);
        temp = null;
    }
}

5)应用

6、希尔排序

1)原理:

    (shellSort)现将待排序的数组元素分成多个子序列,使得每个子序列的元素个数相对较少,然后对各个子序列分别进行直接插入排序,待整个待排序列“基本有序”后,最后在对所有元素进行一次直接插入排序。因此,我们要采用跳跃分割的策略:将相距某个“增量”的记录组成一个子序列,这样才能保证在子序列内分别进行直接插入排序后得到的结果是基本有序而不是局部有序。希尔排序是对直接插入排序算法的优化和升级

 

2)步骤:

1.先取一个正整数 d1(d1 < n),把全部记录分成 d1 个组,所有距离为 d1 的倍数的记录看成一组,然后在各组内进行插入排序
2.然后取 d2(d2 < d1)
重复上述分组和排序操作;直到取 di = 1(i >= 1) 位置,即所有记录成为一个组,
3.最后对这个组进行插入排序。一般选 d1 约为 n/2,d2 为 d1 /2, d3 为 d2/2 ,…, di = 1。
列如:我们有一个数组[ 13 14 94 33 82 25 59 94 65 23 45 27 73]如果我们以步长为6开始进行排序,我们可以通过将这列表放在有6列

3)算法分析:

   希尔排序的关键并不是随便分组后各自排序,而是将相隔某个“增量”的记录组成一个子序列,实现跳跃式移动,使得排序的效率提高。需要注意的是,增量序列的最后一个增量值必须等于1才行。另外,由于记录是跳跃式的移动,希尔排序并不是一种稳定的排序算法。

希尔排序时间复杂度
   希尔排序的时间复杂度与增量(即,步长gap)的选取有关。例如,当增量为1时,希尔排序退化成了直接插入排序,此时的时间复杂度为O(N²),而Hibbard增量的希尔排序的时间复杂度为O(N3/2)。

4)Java实现:

package com.wei.arithmetic.base;

import com.wei.arithmetic.base.sort.abs.AbstractSort;

import java.io.Serializable;
import java.util.Comparator;

public class ShellSort<T> extends AbstractSort<T> {

    public ShellSort(Comparator<T> comparator) {
        super(comparator);
    }

    public ShellSort() {
    }


    @Override
    public int[] sort(int[] array, int order) {
        if (array == null || array.length <= 1) {
            return array;
        }
        //每次取步长为array.length/2
        for (int step = array.length >> 1; step > 0; step = step >> 1) {
            //根据同步长数据分成step组进行直接插入排序
            for (int j = step; j < array.length; j += step) {
                int temp = array[j];
                int k = j - step;
                int index = -1;
                //降序排序
                if (order == -1) {
                    //
                    while (k >= 0) {
                        if (temp > array[k]) {
                            //后移一位
                            array[k + step] = array[k];
                            index = k;
                        }
                        k -= step;
                    }
                } else {//升序排序
                    while (k >= 0) {
                        if (temp < array[k]) {
                            //后移一位
                            array[k + step] = array[k];
                            index = k;
                        }
                        k -= step;
                    }
                }
                //将array[j]填入index位置
                if (index != -1) {
                    array[index] = temp;
                }
            }
        }
        return array;
    }

    @Override
    public T[] sort(T[] array, int order) {
        if (array == null || array.length <= 1) {
            return array;
        }
        //每次取步长为array.length/2
        for (int step = array.length >> 1; step > 0; step = step >> 1) {
            //根据同步长数据分成step组进行直接插入排序
            for (int j = step; j < array.length; j += step) {
            	//保存需要插入排序的数据
                T temp = array[j];
                int k = j - step;
              	//保存tmep最终需要插入的位置
                int index = -1;
                while (k >= 0) {
                    boolean bl = (comparator != null && comparator.compare(temp, 										array[k]) > 0)
                            || ((Comparable & Serializable) temp).compareTo(array[k]) > 								0;
                    //1、(order == -1 && bl) 降序排序;2、(order != -1 && !bl) 升序排序
                    if ((order == -1 && bl) || (order != -1 && !bl)) {
                        //后移一位
                        array[k + step] = array[k];
                        index = k;
                    }
                    k -= step;
                }
                //将array[j]填入index位置
                if (index != -1) {
                    array[index] = temp;
                }
            }
        }

        return array;
    }

}

5)应用

7、堆排序

1)原理:

 堆通常是一个可以被看做一棵树,它满足下列性质:
  [性质一] 堆中任意节点的值总是不大于(不小于)其子节点的值;
  [性质二] 堆总是一棵完全树。
  将任意节点不大于其子节点的堆叫做最小堆或小根堆,而将任意节点不小于其子节点的堆叫做最大堆或大根堆。常见的堆有二叉堆、左倾堆、斜堆、二项堆、斐波那契堆等等。
 二叉堆的定义
 二叉堆是完全二元树或者是近似完全二元树,它分为两种:最大堆和最小堆。
 最大堆:父结点的键值总是大于或等于任何一个子节点的键值;最小堆:父结点的键值总是小于或等于任何一个子节点的键值。
 假设"第一个元素"在数组中的索引为 0 的话,则父节点和子节点的位置关系如下:
 (01) 索引为i的左孩子的索引是 (2*i+1);
 (02) 索引为i的右孩子的索引是 (2*i+2);
 (03) 索引为i的父结点的索引是 floor((i-1)/2);

 

2)步骤:

1、构建初始堆,将待排序列构成一个大顶堆(或者小顶堆),升序大顶堆,降序小顶堆;
2、将堆顶元素与堆尾元素交换,并断开(从待排序列中移除)堆尾元素。
3、重新构建堆。
4重复2~3,直到待排序列中只剩下一个元素(堆顶元素)。

3)算法分析:


4)Java实现:

实现了一个堆数据结构,调用remove方法每次拿出第一个元素即可排序成功。

public int[] sort(int[] array, int order) {
        if (array == null || array.length <= 1){
            return array;
        }
        //调整成堆结构数组结构
        createHead(array, order);
        for (int i = array.length - 1; i > 0; i--) {
            //调整堆结构
            swap(array, 0, i);
            adjustmentHead(array, i, order);
        }
        return array;
    }

    private void adjustmentHead(int[] array, int end, int order) {
        int index = 0;
        while (index < end && getLeftIndex(index) <= end) {
            if (getRightIndex(index) >= end) {
                if (order != -1){
                    //向左遍历
                    if(array[index] > array[getLeftIndex(index)]){
                        swap(array, index, getLeftIndex(index));
                    }
                    break;
                }else {
                    //向左遍历
                    if(array[index] < array[getLeftIndex(index)]){
                        swap(array, index, getLeftIndex(index));
                    }
                    break;
                }
            }else {
                if(order != -1){
                    //父节点满足堆性质,直接返回
                    if(array[index] > array[getLeftIndex(index)] && array[index] > array[getRightIndex(index)]){
                        break;
                    }
                    //向右遍历
                    if(array[getRightIndex(index)] > array[getLeftIndex(index)]){
                        swap(array, index,  getRightIndex(index));
                        index = getRightIndex(index);
                    }else {//向左遍历
                        swap(array, index,  getLeftIndex(index));
                        index = getLeftIndex(index);
                    }
                }else {
                    //父节点满足堆性质,直接返回
                    if(array[index] < array[getLeftIndex(index)] && array[index] < array[getRightIndex(index)]){
                        break;
                    }
                    //向右遍历
                    if(array[getRightIndex(index)] < array[getLeftIndex(index)]){
                        swap(array, index,  getRightIndex(index));
                        index = getRightIndex(index);
                    }else {//向左遍历
                        swap(array, index,  getLeftIndex(index));
                        index = getLeftIndex(index);
                    }
                }
            }

        }
    }

    /**
     *
     * @param array
     * @param order
     */
    private void createHead(int[] array, int order) {
        int tempIndex;
        //依次遍历每个元素,使其成为最大堆或者最小堆结构
        for (int i = 1; i < array.length; i++) {
            tempIndex = i;
            //降序
            if(order != -1){
                //向上遍历,与父节点比较,使其满足最大堆或者最小堆结构
                while (getParentIndex(tempIndex) >= 0){
                    if(array[getParentIndex(tempIndex)] < array[tempIndex]){
                        swap(array, tempIndex, getParentIndex(tempIndex));
                        tempIndex = getParentIndex(tempIndex);
                    }else {
                        break;
                    }
                    if(tempIndex == 0){
                        break;
                    }
                }
            }else {
            //升序
                while (getParentIndex(tempIndex) >= 0){
                    if(array[getParentIndex(tempIndex)] > array[tempIndex]){
                        swap(array, tempIndex, getParentIndex(tempIndex));
                        tempIndex = getParentIndex(tempIndex);
                    }else {
                        break;
                    }
                    if(tempIndex == 0){
                        break;
                    }
                }
            }
        }
    }

    private int getParentIndex(int index){
        return (index - 1) >> 1;
    }

    private int getLeftIndex(int index){
        return (index << 1) + 1;
    }

    private int getRightIndex(int index){
        return (index << 1) + 2;
    }

8、计数排序

1)原理:

	加入输入一个数x,如果我们可以找到比x小的数有几个,那么就可以直接将x放入到对应的输出数组的位置。
比如输入一个数x=12,发现在输入的数据中,比12小的有4个,那么毫无疑问12就该排在第五位

2)步骤:

找出待排序的数组中最大和最小的元素;
统计数组中每个值为i的元素出现的次数,存入数组C的第i项;
对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加);
反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1。

 

3)算法分析:

计数排序是一个稳定的排序算法。当输入的元素是 n 个 0到 k 之间的整数时,时间复杂度是O(n+k),空间复杂度也是O(n+k),其排序速度快于任何比较排序算法。当k不是很大并且序列比较集中时,计数排序是一个很有效的排序算法。

4)java代码:

public int[] sort(int[] array, int order) {
        if (array == null || array.length <= 1) {
            return array;
        }
        int[] re = ArithmeticUtils.getMaxAndMin(array);
        int[] buckets = new int[re[1] - re[0]];
        //计数
        for (int i = 0; i < array.length; i++) {
            buckets[array[i] - re[0]]++;
        }
        int j = 0;
        //升序排序
        if (order != -1) {
            for (int i = 0; i < buckets.length; i++) {
                while (buckets[i] > 0) {
                    array[j++] = i + re[0];
                    buckets[i]--;
                }
            }
         //降序排序
        } else {
            for (int i = buckets.length - 1; i >= 0 ; i--) {
                while (buckets[i] > 0) {
                    array[j++] = i + re[0];
                    buckets[i]--;
                }
            }
        }
        return new int[0];
    }
    
    public static int[] getMaxAndMin(int[] array) {
        if (array == null || array.length == 0) {
            return array;
        }
        int[] re = new int[2];
        int start = 1;
        int end = array.length - 1;
        int max = array[0];
        int min = array[0];
        int maxIndex;
        int minIndex;
        while (start < end) {
            if (array[start] >= array[end]) {
                maxIndex = start;
                minIndex = end;
            } else {
                maxIndex = end;
                minIndex = start;
            }
            max = Math.max(max, array[maxIndex]);
            min = Math.min(min, array[minIndex]);
            start++;
            end--;
        }
        re[0] = Math.min(min, array[start]);
        re[1]  = Math.max(max, array[start]) + 1;
        return  re;
    }

9、桶排序

1)原理:

桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。桶排序 (Bucket sort)的工作的原理:假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排)。

2)步骤:

设置一个定量的数组当作空桶;
遍历输入数据,并且把数据一个一个放到对应的桶里去;
对每个不是空的桶进行排序;
从不是空的桶里把排好序的数据拼接起来。

3)算法分析:

桶排序最好情况下使用线性时间O(n),桶排序的时间复杂度,取决与对各个桶之间数据进行排序的时间复杂度,因为其它部分的时间复杂度都为O(n)。很显然,桶划分的越小,各个桶之间的数据越少,排序所用的时间也会越少。但相应的空间消耗就会增大。

4)Java代码:

public int[] sort(int[] array, int order) {
        if (array == null || array.length <= 1) {
            return array;
        }
        //获取排序数组中的最大值与最小值
        int[] maxAndMin = ArithmeticUtils.getMaxAndMin(array);
        //获取桶的数量,桶数量越多时间复杂度越小
        int number = (maxAndMin[1] - maxAndMin[0]) / bucketRange + 1;

        List<LinkedList<Integer>> buckets = new ArrayList<>(number);
        //创建桶
        for (int i = 0; i < number; i++) {
            buckets.add(new LinkedList<>());
        }
        //放入相应桶中
        for (int i = 0; i < array.length; i++) {
            insertBucket(array[i], buckets.get((array[i] - maxAndMin[0]) / 						this.bucketRange));
        }
        //在放入排序数组中
        int index = 0;
        for (int i = 0; i < buckets.size(); i++) {
            //降序
            if (order == -1) {
                ListIterator<Integer> it = buckets.get(i).listIterator();
                while (it.hasNext()) {
                    int temp = (array.length - 1 - index);
                    array[temp] = it.next();
                    index ++;
                }
            } else {//升序
                ListIterator<Integer> it = buckets.get(i).listIterator();
                while (it.hasNext()) {
                    array[index ++] = it.next();
                }
            }
        }
        return array;
    }
    
    private void insertBucket(int element, LinkedList<Integer> bucket) {
        ListIterator<Integer> it = bucket.listIterator();
        boolean isInsert = false;
        while (it.hasNext()) {
            if (it.next().compareTo(element) > 0) {
                it.previous();
                it.add(element);
                isInsert = true;
                break;
            }
        }
        if (!isInsert) {
            bucket.add(element);
        }
    }

10、基数排序

1)原理:

	基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。

2)步骤:

取得数组中的最大数,并取得位数;
arr为原始数组,从最低位开始取每个位组成radix数组;
对radix进行计数排序(利用计数排序适用于小范围数的特点);

3)算法分析:

基数排序基于分别排序,分别收集,所以是稳定的。但基数排序的性能比桶排序要略差,每一次关键字的桶分配都需要O(n)的时间复杂度,而且分配之后得到新的关键字序列又需要O(n)的时间复杂度。假如待排数据可以分为d个关键字,则基数排序的时间复杂度将是O(d*2n) ,当然d要远远小于n,因此基本上还是线性级别的。
基数排序的空间复杂度为O(n+k),其中k为桶的数量。一般来说n>>k,因此额外空间需要大概n个左右。

区别主要是桶的使用方法上有明显差异:
1、基数排序:根据键值的每位数字来分配桶
2、计数排序:每个桶只存储单一键值
3、桶排序:每个桶存储一定范围的数值

4)Java代码:

 public int[] sort(int[] array, int order) {
        if (array == null || array.length <= 1) {
            return array;
        }
        //获取排序数组中的最大值与最小值
        int[] maxAndMin = ArithmeticUtils.getMaxAndMin(array);
        //获取最大值的长度,即位数
        int length = String.valueOf(maxAndMin[1]).length();
        //排序
        radixSort(array, length, order);
        return array;
    }

    private void radixSort(int[] array, int length, int order) {
        List<LinkedList<Integer>> buckets = new ArrayList<>();
        for (int i = 1; i <= length; i++) {
            buckets.clear();
            //创建10桶
            for (int k = 0; k < 10; k++) {
                buckets.add(new LinkedList<>());
            }
            for (int j = 0; j < array.length; j++) {
                insertBucket(array[j], buckets.get(ArithmeticUtils.getNumberByIndenx(array[j], length)));
            }
            //在放入排序数组中
            int index = 0;
            for (int m = 0; m < buckets.size(); m++) {
                //降序
                if (order == -1) {
                    ListIterator<Integer> it = buckets.get(m).listIterator();
                    while (it.hasNext()) {
                        int temp = (array.length - 1 - index);
                        array[temp] = it.next();
                        index ++;
                    }
                } else {//升序
                    ListIterator<Integer> it = buckets.get(m).listIterator();
                    while (it.hasNext()) {
                        array[index ++] = it.next();
                    }
                }
            }
        }

    }

    /**
     * 插入排序的方式对桶内数据进行排序
     * @param element
     * @param bucket
     */
    private void insertBucket(int element, LinkedList<Integer> bucket) {
        ListIterator<Integer> it = bucket.listIterator();
        boolean isInsert = false;
        while (it.hasNext()) {
            if (it.next().compareTo(element) > 0) {
                it.previous();
                it.add(element);
                isInsert = true;
                break;
            }
        }
        if (!isInsert) {
            bucket.add(element);
        }
    }

11、二分查找

1)原理:

二分法查找,也称为折半法,是一种在有序数组中查找特定元素的搜索算法。

2)步骤:

(1)首先,从数组的中间元素开始搜索,如果该元素正好是目标元素,则搜索过程结束,否则执行下一步。
(2)如果目标元素大于/小于中间元素,则在数组大于/小于中间元素的那一半区域查找,然后重复步骤(1)的操作。
(3)如果某一步数组为空,则表示找不到目标元素。

3)Java代码:

public static int binarySearch(int[] array, int target){
        if(array != null && array.length > 0){
            int start = 0;
            int end = array.length - 1;
            int mid;
            //判断数组升序降序
            boolean asc = false;
            if(array.length >= 2 && array[0] < array[1]){
                asc = true;
            }
            //start + 1 < end 保证最后剩余两个数退出循环
            while (start + 1 < end){
                mid = start + (end - start) / 2;
                if(array[mid] == target){
                    return mid;
                }else if(array[mid] > target){
                    if (asc) {
                        end = mid;
                    }else {
                        start = mid;
                    }
                }else {
                    if (asc) {
                        start = mid;
                    }else {
                        end = mid;
                    }
                }
            }
            if(array[start] == target){
                return start;
            }
            if(array[end] == target){
                return end;
            }
        }
        return -1;
    }

4)算法分析:

二分法查找的时间复杂度O(logn)
优点是比较次数少,查找速度快,平均性能好;
其缺点是要求待查表为有序表,且插入删除困难。
因此,折半查找方法适用于不经常变动而查找频繁的有序列表。

5)应用:

二分查找有关题目:
(1)给定有序可序列,并且是分两端段有序,二分查找target 列如: [9,12,14,15,18,19,  1,2,4,5,7,8]
(2)找峰值
(3)给定一个数组L[238, 797, 123] 求平均分成K组的最大值

12、布隆过滤器

1)原理:

布隆过滤器是可以用于判断一个元素是不是在一个集合里,并且相比于其它的数据结构,布隆过滤器在空间和时间方面都有巨大的优势。布隆过滤器存储空间和插入/查询时间都是常数。但是它也是拥有一定的缺点:布隆过滤器是有一定的误识别率以及删除困难的

2)步骤:

1. 首先需要k个hash函数,每个函数可以把key散列成为1个整数
2. 初始化时,需要一个长度为n比特的数组,每个比特位初始化为0
3. 某个key加入集合时,用k个hash函数计算出k个散列值,并把数组中对应的比特位置为1
4. 判断某个key是否在集合时,用k个hash函数计算出k个散列值,并查询数组中对应的比特位,如果所有的比特位都是1,认为在集合中。

3)算法分析:


4)应用:


13 深度优先、广度优先

1)原理:

  				   1
                /     \
               2       3
             / / \   /  \ \
            4  5  6  7  8  9
深度优先(DFS即Depth First Search)。其过程简要来说是对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次。对于上面的例子来说深度优先遍历的结果就是:1,2,4,5,6,3,7,8,9.(假设先走子节点的的左侧)。  
广度优先(BFS即Breadth FirstSearch)。其过程检验来说是对每一层节点依次访问,访问完一层进入下一层,而且每个节点只能访问一次。对于上面的例子来说,广度优先遍历的 结果是:1,2,3,4,5,6,7,8,9(假设每层节点从左到右访问)

2)步骤:

深度优先遍历各个节点,需要使用到栈(Stack)这种数据结构。stack的特点是是先进后出。整个遍历过程如下:
	首先将1节点压入栈中,stack(1);
	将1节点弹出,同时将1的子节点3,2压入栈中,此时2在栈的顶部,stack(2,3);
	将2节点弹出,同时将2的子节点6,5,4压入栈中,此时栈4顶部,stack(4,5,6,3)
	将4节点弹出,没有子节点压入,此时5在栈的顶部,stack(5,6,3)
	将3弹出,同时将3子节点9,8,7压入,stack(7, 8, 9)

广度优先遍历各个节点,需要使用到队列(Queue)这种数据结构,queue的特点是先进先出,其实也可以使用双端队列,区别就是双端队列首尾都可以插入和弹出节点。整个遍历过程如下:
    首先将1节点插入队列中,queue(1);
    将1节点弹出,同时将1的子节点2,3插入队列中,此时2在队列首,3在队列尾部,queue(2,3);
    将2节点弹出,同时将2的子节点4,5,6插入队列中,此时3在队列首,6在队列尾部,queue(6,5,4,3);
    将3节点弹出,同时将3的子节点7,8,9插入队列中,此时4在队列首,9在队列尾部,				    	queue(9,8,7,6,5,4);
      

3)Java代码:

package com.wei.arithmetic.find;
import com.alibaba.fastjson.JSON;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.Stack;
public class DfsAndBfs<T> {
    /**
     * 根节点
     */
    private Node<T> root;

    private int size;

    public int getSize() {
        return size;
    }

    public Node<T> getRoot() {
        return root;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public Node<T> addChild(Node<T> parent, T element) {
        if (element == null) {
            return null;
        }
        size++;
        if(root == null){
            this.root = new Node<>(element);
            return this.root;
        }else {
            if(parent == null){return null;}
            List<Node<T>> childrens = parent.getChildren() == null ? new ArrayList<>() : 			 parent.getChildren();
            Node<T> node = new Node<>(element);
            childrens.add(node);
            parent.setChildren(childrens);
            return node;
        }
    }

    static class Node<T> {
        private T data;
        //孩子树
        private List<Node<T>> children;

        public Node(T data) {
            this.data = data;
        }

        public List<Node<T>> getChildren() {
            return children;
        }
        public void setChildren(List<Node<T>> children) {
            this.children = children;
        }

        public T getData() {
            return data;
        }

        public void setData(T data) {
            this.data = data;
        }
    }

    /**
     * 广度优先
     * @param bfs
     * @param <T>
     * @return
     */
    public  <T> List<T> bfs(DfsAndBfs<T> bfs) {
        if (bfs == null || bfs.isEmpty()) {
            return new ArrayList<>();
        }
        List<T> result = new ArrayList<>(bfs.size);
        Queue<Node<T>> queue = new ArrayDeque<>();
        queue.add(bfs.getRoot());
        while (!queue.isEmpty()){
            Node<T> remove = queue.remove();
            result.add(remove.data);
            if(remove.getChildren() != null && remove.getChildren().size() > 0){
                queue.addAll(remove.getChildren());
            }
        }
        return result;
    }

    /**
     * 深度优先
     * @param dfs
     * @param <T>
     * @return
     */
    public <T> List<T> dfs(DfsAndBfs<T> dfs) {
        if (dfs == null || dfs.isEmpty()) {
            return new ArrayList<>();
        }
        List<T> result = new ArrayList<>(dfs.size);
        Stack<Node<T>> stack = new Stack<>();
        Node<T> root = dfs.getRoot();
        stack.push(root);
        while (!stack.isEmpty()) {
            //取出
            Node<T> pop = stack.pop();
            result.add(pop.data);
            if(pop.getChildren() != null && pop.getChildren().size() > 0){
                for (int i = pop.getChildren().size() - 1; i >= 0; i--) {
                    stack.push(pop.getChildren().get(i));
                }
            }
        }
        return result;
    }


    public static void main(String[] args) {
//                     1
//                  /     \
//                2       3
//              / / \   /  \ \
//             4  5  6  7  8  9
//           /  \
//          10  11
        //构建如上树结构数据
        DfsAndBfs<Integer> db = new DfsAndBfs<>();
        Node<Integer> root = db.addChild(null, 1);
        Node<Integer> node = db.addChild(root, 2);
        Node<Integer> node1 = db.addChild(root, 3);
        Node<Integer> node2 = db.addChild(node, 4);
        db.addChild(node2, 10);
        db.addChild(node2, 11);
        db.addChild(node, 5);
        db.addChild(node, 6);
        db.addChild(node1, 7);
        db.addChild(node1, 8);
        db.addChild(node1, 9);
        //深度优先打印结果:[1,2,4,10,11,5,6,3,7,8,9]
        System.out.println(JSON.toJSON(db.dfs(db)));
        //广度优先打印结果:[1,2,3,4,5,6,7,8,9,10,11]
        System.out.println(JSON.toJSON(db.bfs(db)));
    }

}

4)应用:

树的查找遍历

14、贪心算法

1)原理:


2)步骤:


3)算法分析:


4)应用:


15、回溯算法

1)原理:

	一种选优搜索法,又称试探法。利用试探性的方法,在包含问题所有解的解空间树中,将可能的结果搜索一遍,从而获得满足条件的解。搜索过程采用深度遍历策略,并随时判定结点是否满足条件要求,满足要求就继续向下搜索,若不满足要求则回溯到上一层,这种解决问题的方法称为回溯法。当问题是要求满足某种性质(约束条件)的所有解或最优解时,往往使用回溯法。
	回溯法的实现方法有两种:递归和递推(也称迭代)

2)步骤:

1、针对给定问题,定义问题的解空间树;
2、确定易于搜索的解空间结构;
3、以深度优先方式搜索解空间,并且在搜索过程中用剪枝函数避免无效搜索;
4、用回溯法求解问题,重点是设计问题的解空间树,其解题过程则是深度遍历解空间树的过程。

3)java实现

 

4)算法分析:


5)应用:


16、剪枝算法

17、朴素贝叶

18、推荐算法

19、最小生成树算法

20、最短路径算法

1)原理:

 

2)步骤:

3)算法分析:

4)Java实现

 

5)应用


二、提升类算法总结

1、搜索

1、强联通划分

2、割点、桥

3、双联通

2、图论

1、最小生成树

2、二分图染色

3、二分图匹配

4、拓扑排序

5、最短路

6、Floyd

7、Dijkstra

8、SPFA

9、网络流&Dinic算法

10、最小费用流

11、上下限网络流

12、差分约束系统

3、树

1、树的直径

2、树的重心

3、点分治

4、倍增LCA

5、虚树

6、DFS序

7、树链剖分

4、数据结构

1、堆

​ 1)定义

堆通常是一个可以被看做一棵树的数组对象。堆总是满足下列性质:
	[性质一] 堆中任意节点的值总是不大于(不小于)其子节点的值;
	[性质二] 堆总是一棵完全树。
	常见的堆有二叉堆、左倾堆、斜堆、二项堆、斐波那契堆等等
	堆的定义:n个元素的序列{k1,k2,ki,…,kn}当且仅当满足下关系时,称之为堆。
(ki <= k2i,ki <= k2i+1)或者(ki >= k2i,ki >= k2i+1), (i = 1,2,3,4…n/2)
假设"第一个元素"在数组中的索引为 0 的话,则父节点和子节点的位置关系如下:
 (1) 索引为i的左孩子的索引是 (2*i+1);
 (2) 索引为i的右孩子的索引是 (2*i+2);
 (3) 索引为i的父结点的索引是 floor((i-1)/2);

二叉堆java代码实现

public class HeadArray<T> implements Serializable {

    /**
     * 数组存储数据
     */
    private Object[] elementData;

    /**
     * 元素总数
     */
    private int size = 0;

    /**
     * 是否是最大堆
     */
    private final boolean isMaxHead;

    /**
     * 默认初始数组大小
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * 比较器
     */
    private final Comparator<T> comparator;


    public HeadArray(Comparator<T> comparator) {
        elementData = new Object[DEFAULT_CAPACITY];
        this.comparator = comparator;
        this.isMaxHead = true;
    }

    public HeadArray() {
        elementData = new Object[DEFAULT_CAPACITY];
        this.comparator = null;
        this.isMaxHead = true;
    }

    public HeadArray(Comparator<T> comparator, int size) {
        elementData = new Object[size];
        this.comparator = comparator;
        this.isMaxHead = true;
    }

    public HeadArray(int size) {
        elementData = new Object[size];
        this.comparator = null;
        this.isMaxHead = true;
    }

    public HeadArray(Comparator<T> comparator, boolean isMaxHead) {
        elementData = new Object[DEFAULT_CAPACITY];
        this.comparator = comparator;
        this.isMaxHead = isMaxHead;
    }

    public HeadArray(boolean isMaxHead) {
        elementData = new Object[DEFAULT_CAPACITY];
        this.comparator = null;
        this.isMaxHead = isMaxHead;

    }

    public HeadArray(Comparator<T> comparator, int size, boolean isMaxHead) {
        elementData = new Object[size];
        this.comparator = comparator;
        this.isMaxHead = isMaxHead;
    }

    public HeadArray(int size, boolean isMaxHead) {
        elementData = new Object[size];
        this.comparator = null;
        this.isMaxHead = isMaxHead;
    }

    /**
     * 添加元素
     * @param element
     */
    public void add(T element) {
        if (element == null) {
            throw new NullPointerException("not allow add null element");
        }
        if(isContains(element)){
            return;
        }
        T t = get(0);
        if (t == null) {
            //初始化初始节点
            elementData[0] = element;
        } else {
            if (size() + 1 > elementData.length) {
                //扩容
                dilatationArray();
            }
            elementData[size] = element;
            fixAfterInsertionUp(size);
        }
        size++;
    }

    public T set(int index, T element) {
        if(index < 0 || index > size() || findElementIndex(element) != -1){
            throw new IndexOutOfBoundsException("set index out of zhe data length or set element is exist");
        }
        T old = get(index);
        if(compareTwoElement(old, element) != 0){
            elementData[index] = element;
            //向上遍历找到element位置
            fixAfterInsertionUp(index);
            //向下遍历找到element位置
            fixAfterInsertionDown(index);
        }
        return old;
    }

    public boolean addAll(T[] element) {
        if (element == null || element.length == 0) {
            return false;
        }

        return true;
    }


    /**
     * 移除指定元素
     * @param element
     * @return
     */
    public boolean remove(T element) {
        int index = findElementIndex(element);
        if(index == -1){
            return false;
        }
        return remove(index);
    }


    /**
     * 移除指定位置上的元素
     * @param index
     * @return
     */
    public boolean remove(int index) {
        if (index < 0 || index > size()) {
            throw new IndexOutOfBoundsException("remove index out of zhe data length");
        }
        elementData[index] = elementData[size - 1];
        elementData[size - 1] = null;
        size--;
        fixAfterInsertionDown(index);
        return true;
    }


    /**
     * 是否包含 element元素
     *
     * @param element
     * @return
     */
    public boolean isContains(T element) {
        if (element == null) {
            return false;
        }
        int index = findElement(element, 0);
        return index >= 0;
    }

    /**
     * 获取指定元素下表位置
     *
     * @param element
     * @return
     */
    public int findElementIndex(T element) {
        if (element == null) {
            return -1;
        }
        return findElement(element, 0);
    }

    private T getRight(int index){
        if(index * 2 + 2 > size - 1){
            return null;
        }
        return (T) elementData[index * 2 + 2];
    }

    private T getLeft(int index){
        if(index * 2 + 1 > size - 1){
            return null;
        }
        return (T) elementData[index * 2 + 1];
    }

    private T getParent(int index){
        return (T) elementData[(index - 1) >> 1];
    }


    private int getRightIndex(int index){
        if(index * 2 + 2 > size - 1){
            throw new IndexOutOfBoundsException("index out of exception: " + (index * 2 + 2));
        }
        return index * 2 + 2;
    }

    private int getLeftIndex(int index){
        if(index * 2 + 1 > size - 1){
            throw new IndexOutOfBoundsException("index out of exception: " + (index * 2 + 1));
        }
        return index * 2 + 1;
    }

    private int getParentIndex(int index){
        if(index > size - 1){
            throw new IndexOutOfBoundsException("index out of exception: " + index);
        }
        return (index - 1) >> 1;
    }

    /**
     * 将新插入的数据调整位置,使其满足堆特性
     */
    private void fixAfterInsertionUp(int index) {
        if(index <= 0){return;}
        //与父节点比较大小
        int parentIndex = (index - 1) >> 1;
        T element = get(index);
        int temp = index;
        while ((isMaxHead && compareTwoElement(element, get(parentIndex)) == 1)
                || (!isMaxHead && compareTwoElement(element, get(parentIndex)) == -1)) {
            elementData[temp] = elementData[parentIndex];
            elementData[parentIndex] = element;
            temp = parentIndex;
            if (parentIndex == 0) {
                break;
            }
            parentIndex = (parentIndex - 1) >> 1;
        }
    }

    private void fixAfterInsertionDown(int index) {
        T temp;
        while (true) {
            temp = get(index);
            T left = getLeft(index);
            T right = getRight(index);
            if (left == null) {
                break;
            }
            int leftIndex = getLeftIndex(index);
            //最大堆
            if (isMaxHead) {
                if (left != null && right == null) {
                    if (compareTwoElement(left, (T) elementData[index]) > 0) {
                        elementData[index] = elementData[leftIndex];
                        elementData[leftIndex] = temp;
                    }
                    break;
                }
                int rightIndex = getRightIndex(index);
                //对tmp, left, right降序排序
                T[] sort = sort(temp, left, right);
                if (sort[0] == temp) {
                    break;
                } else if (sort[0] == left) {
                    elementData[index] = elementData[leftIndex];
                    elementData[leftIndex] = temp;
                    index = leftIndex;
                } else {
                    elementData[index] = elementData[rightIndex];
                    elementData[rightIndex] = temp;
                    index = rightIndex;
                }
                //最小堆
            } else {
                if (left != null && right == null) {
                    if (compareTwoElement(left, (T) elementData[index]) < 0) {
                        elementData[index] = elementData[leftIndex];
                        elementData[leftIndex] = temp;
                    }
                    break;
                }
                int rightIndex = getRightIndex(index);
                T[] sort = sort(temp, left, right);
                if (sort[2] == temp) {
                    break;
                } else if (sort[2] == left) {
                    elementData[index] = elementData[leftIndex];
                    elementData[leftIndex] = temp;
                    index = leftIndex;
                } else {
                    elementData[index] = elementData[rightIndex];
                    elementData[rightIndex] = temp;
                    index = rightIndex;
                }
            }
        }
    }

    /**
     * 降序排序
     * @param element
     * @return
     */
    private T[] sort(T... element) {
        if (element == null || element.length <= 1) {
            return element;
        }
        T temp;
        int index;
        for (int i = 0; i < element.length - 1; i++) {
            index = i + 1;
            temp = element[index];
            for (int j = i; j >= 0; j--) {
                if (compareTwoElement(temp, element[j]) > 0) {
                    element[j + 1] = element[j];
                    index = j;
                }
            }
            element[index] = temp;
        }
        return element;
    }


    private int findElement(T element, int index) {
        if (index > size - 1) {
            return -1;
        }
        //比较父节点
        int isParent = compareTwoElement(element, get(index));
        if (isParent == 0) {
            return index;
        }
        //比较左节点
        if (2 * index + 1 > size - 1) {
            return -1;
        }
        int isEqLeft = compareTwoElement(element, get(2 * index + 1));
        if (isEqLeft == 0) {
            return 2 * index + 1;
        }
        //比较右节点
        if (2 * index + 2 > size - 1) {
            return -1;
        }
        int isEqRight = compareTwoElement(element, get(2 * index + 2));
        //System.out.println("index = " + index + ";parent=" + get(index) + ";left=" + get(2 * index + 1) + "right=" + get(2 * index + 2));
        if (isEqRight == 0) {
            return 2 * index + 2;
        }
        int lf = -1;
        int rh = -1;
        //最大堆
        if (isMaxHead) {
            if (isParent == 1) {
                return -1;
            }
            if (isEqLeft == -1) {
                lf = findElement(element, 2 * index + 1);
            }
            if (isEqRight == -1) {
                rh = findElement(element, 2 * index + 2);
            }
        } else {
            //最小堆
            if (isParent == -1) {
                return -1;
            }
            if (isEqLeft == 1) {
                lf = findElement(element, 2 * index + 1);
            }
            if (isEqRight == 1) {
                rh = findElement(element, 2 * index + 2);
            }
        }
        if (lf != -1) {
            return lf;
        } else if (rh != -1) {
            return rh;
        }
        return -1;
    }


    /**
     * 拿到指定位置上的元素
     *
     * @param index
     * @return
     */
    public T get(int index) {
        if (index < 0 || index >= elementData.length) {
            throw new IndexOutOfBoundsException("index out of zhe data length");
        }
        return (T) elementData[index];
    }


    /**
     * 获取数据长度
     *
     * @return
     */
    public int size() {
        return size;
    }


    /**
     * 动态扩容数组大小
     */
    private void dilatationArray() {
        int newLength = elementData.length + (elementData.length >> 1);
        elementData = Arrays.copyOf(elementData, newLength);
    }


    /**
     * 比较两个元素大小
     *
     * @param e1
     * @param e2
     * @return -1:e1<e2  0:e1=e2  1:e1>e2
     */
    private int compareTwoElement(T e1, T e2) {
        int result;
        if (comparator != null) {
            result = comparator.compare(e1, e2);
        } else {
            result = ((Comparable<T> & Serializable) e1).compareTo(e2);
        }
        if (result > 0 && result != 1) {
            result = 1;
        }
        if (result < 0 && result != -1) {
            result = -1;
        }
        return result;
    }

    @Override
    public String toString() {
        return "HeadArray{" +
                "data=" + Arrays.toString(elementData) +
                '}';
    }

    public static void main(String[] args) {
        HeadArray<Integer> dataStructure = new HeadArray<>(true);
        Integer[] re = new Integer[]{66, 33, 13, 34, 19, 14, 88, 22, 44, 77, 90, 31, 43, 10, 2, 12, 29, 55};
        for (int i = 0; i < re.length; i++) {
            dataStructure.add(re[i]);
        }
        System.out.println(dataStructure.toString());
        System.out.println("size == " + dataStructure.size);
        System.out.println("add----------------");
        dataStructure.add(56);
        dataStructure.add(18);
        dataStructure.add(17);
        dataStructure.add(42);
        dataStructure.add(41);
        System.out.println(dataStructure.toString());
        System.out.println("size == " + dataStructure.size);

        System.out.println("remove----------------");
        dataStructure.remove(new Integer(56));
        System.out.println(dataStructure.toString());
        System.out.println("size == " + dataStructure.size);
        for (Integer integer : re) {
            System.out.print("   元素:"+ integer + "--->"+ dataStructure.findElementIndex(integer));
        }
        System.out.println();
        Integer[] sort = new Integer[dataStructure.size];
        dataStructure.set(1, 1);
        System.out.println("set:==" + dataStructure.toString());
        int size = dataStructure.size;
        for (int i = 0; i < size; i++) {
            sort[i] = dataStructure.get(0);
            dataStructure.remove(0);
        }
        System.out.println("sort==" + JSON.toJSON(sort));
    }
}

2、单调队列、单调栈

1)基本概念

单调栈:
   是指一个栈内部的元素具有严格单调性的一种数据结构,分为单调递增栈和单调递减栈。
   其具有以下两个性质:
   1,满足栈底到栈顶的元素具有严格单调性。
   2,满足栈的先进后出特性,越靠近栈顶的元素越后出栈。
单调队列:
	单调队列与单调栈及其相似,把单调栈先进后出的性质改为先进先出既可。 
	元素进队列的过程对于单调递增队列。
	对于一个元素a,如果a>队尾元素,那么直接将a扔进队列,如果a≥队尾元素,则将队尾元素出队列,直到满足 a>队尾元素即可。 

2)单调队列Java实现,基于Java队列实现

package com.wei.datastructure.monotone;

import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.util.ArrayDeque;
import java.util.Comparator;
import java.util.Queue;

/**
 * @Describe
 * @Author wei.peng
 * @Date 2021年09月16日
 */
public class MonotoneQueue<E> {
    private static final Logger log = LoggerFactory.getLogger(MonotoneQueue.class);
    private final ArrayDeque<E> queue;
    protected  Comparator<E> comparator = null;
    /**
     * 是否是递减队列
     */
    private  boolean desc;

    public MonotoneQueue() {
        this.queue = new ArrayDeque<>();
    }

    public MonotoneQueue(boolean desc) {
        this.queue = new ArrayDeque<>();
        this.desc = desc;
    }

    public MonotoneQueue(Comparator<E> comparator) {
        this.queue = new ArrayDeque<>();
        desc = true;
        this.comparator = comparator;
    }

    public MonotoneQueue(Queue<E> queue, boolean desc, Comparator<E> comparator) {
        this.queue = new ArrayDeque<>();
        this.desc = desc;
        this.comparator = comparator;
    }

    public boolean add(E element){
        if(element == null){return false;}
        while (true){
            if(getSize() == 0){
                queue.add(element);
                return true;
            }
            boolean isAdd = (desc && ((comparator != null && comparator.compare(element, queue.getLast()) >= 0)
                    ||(((Comparable<E> & Serializable)element).compareTo(queue.getLast()) >= 0)))
                    || (!desc && ((comparator != null && comparator.compare(element, queue.getLast()) <= 0)
                    ||(((Comparable<E> & Serializable)element).compareTo(queue.getLast()) <= 0)));
            if(!isAdd){
                queue.removeLast();
            }else {
                queue.add(element);
                return true;
            }
        }
    }

    public E getFirst(){
        return queue.getFirst();
    }

    public E getLast(){
        return queue.getLast();
    }

    public boolean remove(E element){
        if(element == null){return false;}
        return queue.remove(element);
    }

    public int getSize() {
        return queue.size();
    }

    @Override
    public String toString() {
        return "MonotoneQueue{" +
                "queue=" + JSON.toJSON(queue) +
                '}';
    }

    public static void main(String[] args) {
        MonotoneQueue<Integer> queue = new MonotoneQueue<>(true);
        queue.add(10);
        queue.add(9);
        queue.add(3);
        queue.add(5);
        queue.add(6);
        queue.add(19);
        queue.add(30);
        queue.add(31);
        queue.add(30);
        queue.add(29);
        queue.add(22);
        queue.add(22);
        System.out.println(queue.toString());
        System.out.println(queue.queue.getLast());
    }
}

3)单调栈java 实现

package com.wei.datastructure.monotone;

import com.alibaba.fastjson.JSON;

import java.io.Serializable;
import java.util.Comparator;
import java.util.Stack;

/**
 * @Describe
 * @Author wei.peng
 * @Date 2021年09月16日
 */
public class MonotoneStack<E> {
    private Stack<E> stack = new Stack<>();
    protected Comparator<E> comparator = null;
    /**
     * 是否是递减栈
     */
    private  boolean desc;

    public MonotoneStack() {
    }

    public MonotoneStack(boolean desc) {
        this.desc = desc;
    }

    public MonotoneStack(Comparator<E> comparator, boolean desc) {
        this.comparator = comparator;
        this.desc = desc;
    }

    /**
     * 最值
     * @return
     */
    public E getLastElement(){
        return stack.peek();
    }

    /**
     * 最值
     * @return
     */
    public E getFirtstElement(){
        return stack.get(0);
    }

    public boolean add(E element) {
        if (element == null) {
            return false;
        }
        while (true) {
            if (stack.size() == 0) {
                stack.push(element);
                return true;
            }
            boolean isAdd = (desc && ((comparator != null && comparator.compare(element, stack.peek()) > 0)
                    || (((Comparable<E> & Serializable) element).compareTo(stack.peek()) > 0)))
                    || (!desc && ((comparator != null && comparator.compare(element, stack.peek()) < 0)
                    || (((Comparable<E> & Serializable) element).compareTo(stack.peek()) < 0)));
            if(!isAdd){
                stack.pop();
            }else {
                stack.push(element);
                return true;
            }
        }
    }

    public int size(){
        return stack.size();
    }

    @Override
    public String toString() {
        return "MonotoneStack{" +
                "stack=" + JSON.toJSON(stack) +
                '}';
    }

    public static void main(String[] args) {
        //因为都是从栈顶添加,所以递增递减从栈顶往栈底看
        MonotoneStack<Integer> stack = new MonotoneStack<>(false);
        stack.add(10);
        stack.add(9);
        stack.add(3);
        stack.add(5);
        stack.add(6);
        stack.add(19);
        stack.add(30);
        stack.add(31);
        stack.add(30);
        stack.add(29);
        stack.add(22);
        //打印结果:MonotoneQueue{queue=[3,5,6,19,22]}
       System.out.println(stack.toString());
    }

}

4)应用

img


3、ST表

1)概念

ST表(Sparse Table,稀疏表)是一种简单的数据结构,主要用来解决RMQ(Range Maximum/Minimum Query,区间最大/最小值查询)问题。
方法:ST算法分成两部分:离线预处理 (nlogn)和 在线查询(O(1))。虽然还可以使用线段树、树状链表等求解区间最值,但是ST算法要比它们更快,而且适用于在线查询。
(1)离线预处理:运用DP思想,用于求解区间最值,并保存到一个二维数组中。
(2)在线查询:对给定区间进行分割。
首先要知道f数组的含义,f[i][j]中i表示左边端点,j表示2^j个长度, 所以f[i,j]表示的是区间为[i,i+2^j-1]这个范围内的最大值,也就是以a[i]为起点连续的2^j个数的最大值.因为元素个数为2^j个,因此从中间平均分红两部分,每一部分的个数都为2^(j-1);假设f[6][3]分为f[6][2]和f[10][2]

4、Splay

5、CT

6、并查集

1)基本概念

	并查集,在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中,并查集是一种树型的数据结构,用于处理一些不相交集合(disjoint sets)的合并及查询问题。常常在使用中以森林来表示
用处:网络中节点间的连接状态,路径问题,朋友问题。
并查集有两个核心操作
查找(find(n);):查找元素所在的集合(这里的集合并不是特指Set这种数据结构,是指广义的数据集合)
  find(n);
合并(union):将两个元素所在的集合合并为一个集合
  union(p,q);
有两种常见的实现思路
1)Quick Find
查找的时间复杂度:O(1)
合并的时间复杂度:O(n)
2)Qucik Union
查找的时间复杂度:O(logn),可以优化至O(α(n)),α(n) < 5
合并的时间复杂度:O(logn),可以优化至O(α(n)),α(n) < 5

7、带权并查集

8、CDQ分治

9、线段树

10、树状数组

11、主席树

12、线段树合并

13、单词查找树

1)基本概念

   单词查找树或键树,是一种树形结构。典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计,它的优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高。
   它有3个基本性质:
 * 根节点不包含字符,除根节点外每一个节点都只包含一个字符。
 * 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。
 * 每个节点的所有子节点包含的字符都不相同

2)Java代码实现

public class TireTree implements Serializable {

    private final Node root = new Node();
    private int size = 0;

    /**
     * 添加元素
     * @param element
     * @return
     */
    public boolean add(String element) {
        if (element == null || "".equals(element.trim())) {
            return false;
        }
        Map<Character, Node> children = this.root.getChildren();
        char[] chars = element.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            //如果包含该字符,则往下继续找
            if (children.containsKey(chars[i])) {
                if (i != chars.length - 1) {
                    children = children.get(chars[i]).children;
                } else {
                    //修改为是单词最后一个字符
                    size++;
                    children.get(chars[i]).setEnd(true);
                }
            } else {//不包含则先创建
                if (i == chars.length - 1) {
                    //添加最后一个元素节点
                    Node last = new Node(chars[i], true);
                    children.put(chars[i], last);
                    size++;
                    return true;
                }
                Node child = new Node(chars[i], false);
                //添加新节点
                children.put(chars[i], child);
                //往下走一步
                children = child.children;
            }
        }
        return false;
    }


    /**
     * 查询target存不存在
     * @param target
     * @return
     */
    public boolean search(String target) {
        if (target == null || "".equals(target.trim())) {
            return false;
        }
        char[] chars = target.toCharArray();
        Map<Character, Node> children = this.root.children;
        for (int i = 0; i < chars.length; i++) {
            if (i == chars.length - 1 && children.containsKey(chars[i]) && children.get(chars[i]).end) {
                return true;
            }
            if (children.containsKey(chars[i])) {
                children = children.get(chars[i]).children;
                continue;
            } else {
                return false;
            }
        }
        return false;
    }

    /**
     * 根据前缀搜索
     *
     * @param pre
     * @return
     */
    public List<String> searchPre(String pre) {
        List<String> result = new ArrayList<>();
        if (pre == null || "".equals(pre.trim())) {
            return result;
        }
        char[] chars = pre.toCharArray();
        Map<Character, Node> children = this.root.children;
        boolean isContains = false;
        for (int i = 0; i < chars.length; i++) {
            if (children.containsKey(chars[i])) {
                if (i == chars.length - 1) {
                    isContains = true;
                    //存在target单词时,添加到返回结果
                    if (children.get(chars[i]).end) {
                        result.add(pre);
                    }
                }
                //往下一步走
                children = children.get(chars[i]).children;
            }
        }
        //说明不存在target前缀的内容
        if (!isContains) {
            return result;
        }
        getElements(pre, children, result);
        return result;
    }

    /**
     * 根据 element 删除搜索元素
     * @param element
     * @return
     */
    public boolean remove(String element) {
        if (element == null || "".equals(element.trim())) {
            return false;
        }
        boolean isMove = removeByElement(element.toCharArray(), this.root, 1);
        if (isMove) {
            size--;
        }
        return isMove;
    }

    private boolean removeByElement(char[] chars, Node node, int end) {
        if(chars.length == end){
            //最后一个节点
            Map<Character, Node> children = node.children;
            Node last = children.get(chars[end - 1]);
            if(last.getChildren() != null && last.getChildren().size() > 0){
                last.end = false;
            }else {
                node.getChildren().remove(chars[end - 1]);
                last = null;
            }
            return true;
        }
        Map<Character, Node> children = node.children;
        Node newNode = children.get(chars[end - 1]);
        boolean isEnd = removeByElement(chars, newNode, end + 1);
        if(newNode.end){
            return false;
        }
        if(isEnd && (newNode.getChildren() == null || newNode.getChildren().size() == 0)){
            node.getChildren().remove(chars[end - 1]);
            newNode = null;
        }
        return true;
    }

    /**
     * @param pre  前缀
     * @param children
     * @param result
     */
    private void getElements(String pre, Map<Character, Node> children, List<String> result) {
        if (children == null || children.size() == 0) {
            return;
        }
        children.forEach((character, node) -> {
            if (node.end) {
                result.add(pre + character);
            }
            getElements(pre + character, node.children, result);
        });
    }

    public List<String> getAllElements() {
        List<String> result = new ArrayList<>();
        if (this.root.children.size() == 0) {
            return result;
        }
        getElements("", root.children, result);
        return result;

    }

    /**
     * 元素个数
     * @return
     */
    public int getSize() {
        return size;
    }

    static class Node implements Serializable {
        private Character character;
        private final Map<Character, Node> children;
        private boolean end = false;

        public Node() {
            this.children = new HashMap<>();
        }

        public Node(Character character, boolean end) {
            this.character = character;
            this.children = new HashMap<>();
            this.end = end;
        }

        public Map<Character, Node> getChildren() {
            return children;
        }

        public Character getCharacter() {
            return character;
        }

        public void setEnd(boolean end) {
            this.end = end;
        }

        public boolean isEnd() {
            return end;
        }
    }


    @Override
    public String toString() {
        return "{\"tireTree\":" + JSON.toJSON(this.getAllElements()) + "}";
    }


    public static void main(String[] args) {
        TireTree tireTree = new TireTree();
        tireTree.add("people");
        tireTree.add("pe");
        tireTree.add("peop");
        tireTree.add("peopl");
        tireTree.add("children");
        tireTree.add("girls");
        tireTree.add("girls1");
        tireTree.add("girls2");
        tireTree.add("girl");
        tireTree.add("boys");
        tireTree.add("boy");
        System.out.println(tireTree.search("children"));
        System.out.println(tireTree.search("childrens"));
        System.out.println(tireTree.search("girl"));
        System.out.println(tireTree.search("boy"));
        System.out.println(tireTree.search("people"));
        System.out.println(tireTree.searchPre("pe"));
        System.out.println(tireTree.toString());
        System.out.println(tireTree.getSize());
        System.out.println(tireTree.remove("peop"));
        System.out.println(tireTree.toString());
        System.out.println(tireTree.getSize());
        System.out.println(tireTree.search("peop"));
    }
}

打印:
true
false
true
true
true
[pe, peop, peopl, people]
{"tireTree":["pe","peop","peopl","people","boy","boys","children","girl","girls","girls1","girls2"]}
11
true
{"tireTree":["pe","peopl","people","boy","boys","children","girl","girls","girls1","girls2"]}
10
false  

5、字符串

1、KMP

2、拓展KMP

3、AC自动机

4、字符串hash

5、Manacher

6、后缀自动机

7、后缀数组

6、动态规划

1、树形DP

2、状压DP

3、数位DP

4、斜率DP

5、区间DP

6、概率DP

7、插头DP

7、数学

1、拓展欧几里得

2、乘法逆元

3、中国剩余定理

4、快速幂

5、矩阵快速幂

6、容斥原理

7、Polya

8、莫比乌斯反演

9、FFT、NTT

10、高斯消元

11、线性基

8、博弈

1、Nim博弈

9、几何

1、线段交、点积、差积

2、凸包

10、其他

1、分块

2、莫队

3、KD树


三、加解密算法

1、RSA

2、AES

3、ECDSA

4、SM2

SM2椭圆曲线公钥密码算法:我国自主知识产权的商用密码算法,是ECC(Elliptic Curve Cryptosystem)算法的一种,基于椭圆曲线离散对数问题,计算复杂度是指数级,求解难度较大,同等安全程度要求下,椭圆曲线密码较其他公钥算法所需密钥长度小很多。

5、SM4

6、ECC

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MPC(Model Predictive Control)即模型预测控制算法,是一种基于最优控制理论的控制方法,常用于动态系统的控制。下面是MPC控制算法的一种代码实现方式: 1. 数据预处理:首先,我们需要获取系统的状态和测量值,以及设定控制目标。这些数据可以通过传感器获取或者根据系统模型进行估计。同时,需要定义系统的约束条件,如控制输入的范围和状态变量的限制值。 2. 状态预测:基于系统模型,我们可以使用数学方法来预测系统未来的状态。这通常使用数值方法(如离散化)或者优化算法(如非线性规划)来实现。通过设置时间窗口和离散化步长,我们可以在每个时间步长内预测系统的状态。 3. 优化问题求解:在MPC中,我们将控制问题建模为一个优化问题。可以使用优化算法来求解这个问题,如线性规划、二次规划、非线性规划等。目标函数是根据控制目标和系统模型构建的,约束条件是根据系统约束和控制器要求定义的。 4. 控制指令生成:通过求解上述优化问题,我们得到了最优的控制输入序列。可以选择其中的第一个输入作为当前时刻的控制指令,发送给执行器执行。然后,基于新的测量数据,进行下一轮的预测、优化和指令。 5. 循环迭代:MPC算法是一种迭代算法,通过不断的预测、优化和控制指令生成,实现对系统的动态控制。每个时间步长都会更新控制指令,从而实现对系统行为的调节。 总结:MPC控制算法代码实现主要涉及数据预处理、状态预测、优化问题求解、控制指令生成和循环迭代等步骤。通过构建系统模型、设置控制目标和约束条件,并使用优化算法求解优化问题,可以实现对系统的模型预测控制。代码实现的具体细节还需要根据具体的系统和算法要求进行进一步的补充和优化。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值