数据结构-review(自用)

队列

环型队列判断满和空:

(rear + 1) % maxSize == front // 满
rear == front // 空

(rear + maxSize - front) % maxSize // 有效数据个数

  • 中缀表达式:(3+4)*5-6
  • 前缀表达式:-*+ 3 4 5 6
  • 后缀表达式:3 4 + 5 x 6 -

排序算法

算法复杂度比较

O(1) < o(log n) < o(n) < o(n log n) < o(n^2) < o(n^3) < o(n^k) <o(2^n) < o(n!)

各自复杂度

平均最差稳定度空间适用场景
冒泡O(N^2)O(N^2)稳定O(1)N小
交换O(N^2)O(N^2)不稳定O(1)N小
选择O(N^2)O(N^2)不稳定O(1)N小
插入O(N^2)O(N^2)稳定O(1)大部分已排好序
基数O(NxK)O(NxK)稳定O(N)-
shellO(NlogN)O(N^S)不稳定O(1)-
快速O(NlogN)O(N^2)不稳定O(NlogN)N大
归并O(NlogN)O(NlogN)稳定O(1)N大
O(NlogN)O(NlogN)不稳定O(1)N大

冒泡排序

从前向后,从下标较小的元素开始,依次比较相邻元素的值,若发现逆序则交换,使值较大的元素逐渐从前移向后面(如果一趟下来没有任何的交换,则说明序列有序,从而减少不必要的比较)

选择排序

  • 从数组中选出最小值,与arr[0]交换
  • 再从arr[1]~arr[n-1]中选出最小值,与arr[1]交换,以此类推

插入排序

  • n个待排序的元素看成一个有序表和无序表,开始有序表只包含一个元素,无序表中包含n-1个元素
  • 每次从无序表中取出第一个元素,把它的排序码一次与有序表元素的排序码进行比较,插入适当位置,成为新的有序表

希尔排序

先按一定增量分组,对每组使用直接插入排序算法排序,随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件被分为一组,算法终止

快速排序

  • 先把数组中的一个数当做基准数,一般会把数组中最左边的数当做基准数,然后从两边开始检索,先从右边检索比基准数小的(如果基准数是最右边的数,则先从左边开始检索),再从左边检索比基准数大的,如果检索到了,就停下,然后交换这两个元素,然后再继续检索
  • 左右指针一旦相遇就停止检索
  • 把基准数和相遇位置的数交换,表示第一轮排序已经结束,此时,基准数左边的全比基准数小,右边全比基准数大
  • 之后先排基准数左边,排完之后再排基准数右边,方式和第一轮一样

归并排序

先分成两块再分成两块,直到最后的两块每块只有一个元素,然后每小块排序

基数排序

将所有待比较数值统一为同样的数位长度,数位较短的前面补0,然后从最低位开始,依次进行一次排序,从最低位排序一直到最高位排序完成后,数列就变成一个有序序列

赫夫曼树

给定n个权值作为n个叶子节点,构造一棵二叉树,若该树的带权路径长度(wpl)达到最小,就称为最优二叉树,也称为哈夫曼树

  • 从小到大排序,每一个数据就是一个节点,每个节点可以看成是一棵最简单的二叉树
  • 取出根节点权值最小的两棵二叉树
  • 组成新的二叉树,该新二叉树的根节点的权值是前面两棵二叉树根节点权值的和
  • 对新的二叉树,以根节点的权值大小再次排序,不断重复1-2-3的步骤,直到数列中,所有的数据都被处理,就得到一颗赫夫曼树

二叉搜索树

【删除一个节点】

  1. 首先判断该节点是 叶子节点 or 只有一个叶子节点的节点 or 有两个叶子节点的节点
  2. 只有一个叶子节点的节点
    1. 判断该节点是其父节点的左子节点还是右子节点
    2. 判断该节点的叶子节点是其左子节点还是右子节点
  3. 有两个叶子节点的节点
    1. 找左子树的最右(最大)节点替上去 或者 找右子树的最左(最小)节点替上去

分治算法

复杂问题分解成小问题

【汉诺塔】

  • 如果是有一个盘:A->C
  • 如果有n>=2个盘,可以看做是两个盘1:最下面的盘;2:上面的所有盘
    • 先把上面的盘A->B
    • 最下面的盘A->C
    • 上面的盘B->C

动态规划

将大问题划分为小问题进行解决,与分治算法不同的是:适用于动态规划算法求解的问题,经分解得到子问题往往不是相互独立的

KMP算法

解决问题

String a 与 String b,判断 b 中是否包含 a,若包含,返回 a 在 b 中的位置下标

思路

  • 当匹配到某个位置,主串与模式串的字符不同时,此时不直接 [从主串下一个位置 模式串从头比较]
    • 模式串的前面部分的字符串内容是与主串的部分字符是相同的
    • 在该模式串"ABACABAD"中,下标0~2的字符是与下标4~6的字符是相同的
  • 从主串不匹配的这个位置,模式串不重头开始,而是比较模式串下标3的字符与主串中的字符是否相同
  • 部分匹配表
    • 以该字符结尾的前缀与后缀最长相同子串的长度

代码

public class Kmp {

    public static void main(String[] args){
        String a = "ABACABAD";
        String b = "BBC ABACABACABAD ABCDABDE";
        int result = kmp(b, a);

        //打印结果:和字符串获得匹配的位置
        System.out.println("resultPosion:"+result);
    }

    /**
     * KMP 匹配
     */
    public static int kmp(String str, String dest){
        //1.首先计算出 部分匹配表
        int[] next = kmpnext(dest);

        System.out.println("next ="+Arrays.toString(next));
        //2.查找匹配位置
        for(int i = 0, j = 0; i < str.length(); i++){
            while(j > 0 && str.charAt(i) != dest.charAt(j)){
                j = next[j-1];
            }
            if(str.charAt(i) == dest.charAt(j)){
                j++;
            }
            if(j == dest.length()){
                return i-j+1;
            }
        }
        return -1;
    }

    /**
     * 计算部分匹配表
     */
    public static int[] kmpnext(String dest){
        int[] next = new int[dest.length()];
        next[0] = 0;

        for(int i = 1,j = 0; i < dest.length(); i++){
            while(j > 0 && dest.charAt(j) != dest.charAt(i)){
                j = next[j - 1];
            }
            if(dest.charAt(i) == dest.charAt(j)){
                j++;
            }
            next[i] = j;
        }
        return next;
    }
}

贪心算法

对问题进行求解时,每一步选择中都采取最好或者最优(即最有利)的选择

与动态规划的区别:

  • 动态规划:模拟所有的可能得到最优解
  • 贪心算法:未模拟所有的可能

迪杰斯特拉算法

最短路径算法,用于计算一个节点到其他节点的最短路径

/* 参数说明:
    *       vs -- 起始顶点(start vertex)。即计算"顶点vs"到其它顶点的最短路径。
    *     prev -- 前驱顶点数组。即,prev[i]的值是"顶点vs"到"顶点i"的最短路径所经历的全部顶点中,位于"顶点i"之前的那个顶点。
    *     dist -- 长度数组。即,dist[i]是"顶点vs"到"顶点i"的最短路径的长度。
    */
public void dijkstra(int vs, int[] prev, int[] dist) {
    // flag[i]=true表示"顶点vs"到"顶点i"的最短路径已成功获取
    boolean[] flag = new boolean[mVexs.length];

    // 初始化
    for (int i = 0; i < mVexs.length; i++) {
        flag[i] = false;          // 顶点i的最短路径还没获取到。
        prev[i] = 0;              // 顶点i的前驱顶点为0。
        dist[i] = mMatrix[vs][i];  // 顶点i的最短路径为"顶点vs"到"顶点i"的权。
    }

    // 对"顶点vs"自身进行初始化
    flag[vs] = true;
    dist[vs] = 0;

    // 遍历mVexs.length-1次;每次找出一个顶点的最短路径。
    int k=0;
    for (int i = 1; i < mVexs.length; i++) {
        // 寻找当前最小的路径;
        // 即,在未获取最短路径的顶点中,找到离vs最近的顶点(k)。
        int min = INF;
        for (int j = 0; j < mVexs.length; j++) {
            if (flag[j]==false && dist[j]<min) {
                min = dist[j];
                k = j;
            }
        }
        // 标记"顶点k"为已经获取到最短路径
        flag[k] = true;

        // 修正当前最短路径和前驱顶点
        // 即,当已经"顶点k的最短路径"之后,更新"未获取最短路径的顶点的最短路径和前驱顶点"。
        for (int j = 0; j < mVexs.length; j++) {
            int tmp = (mMatrix[k][j]==INF ? INF : (min + mMatrix[k][j]));
            if (flag[j]==false && (tmp<dist[j]) ) {
                dist[j] = tmp;
                prev[j] = k;
            }
        }
    }

    // 打印dijkstra最短路径的结果
    System.out.printf("dijkstra(%c): \n", mVexs[vs]);
    for (int i=0; i < mVexs.length; i++)
        System.out.printf("  shortest(%c, %c)=%d\n", mVexs[vs], mVexs[i], dist[i]);
}

弗洛伊德算法

计算图中各个顶点之间的最短路径,每个顶点都是出发访问点

  • 设置顶点vi到顶点vk的最短路径已知为Lik,顶点vk到vj的最短路径为Lkj,顶点vi到vj的路径为Lij,则vi到vj的最短路径为min{(Lik+Lkj), Lij},vk的取值为图中所有顶点,则可获得vi到vj的最短路径

扩展

防止某个数溢出

if (rs * 10 / 10 != rs) { //表明溢出
    return 0;
}

异或

  • 任何数和本身异或则为0
  • 任何数和0异或是本身
  • 异或满足交换律

取模运算为什么是耗时的

n%10 = n - (n/10) * 10

为什么出现拆箱、装箱

  • 泛型:如果除去对象的基本类型外,实现方法是相同的
  • 只有引用类型才能和object类兼容,于是出现了包装类,例如int的包装类是Integer
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值