zoukankan      html  css  js  c++  java
  • 数据结构与算法-绪论

    绪论

    算法:即是在特定计算模型下,旨在解决特定问题的指令序列
    要保证正确性、确定性、可行性、有穷性
    有穷性:

    例子1:HailStone序列

     @Test
        public void test1() {
    
            int n = 7;
            int length = 1;
            while (n > 1) {
                n = ((n % 2) > 0) ? 3 * n + 1 : n / 2;
                length++;
            }
            System.out.println(length);
        }
    

    层级级别:

    例子2:计算任意N个整数之和

    减而治之

    @Test
        public void test4() {
            int[] A = {100, 836, 3236, 5, 16, 26, -3, 89, 69, 43};
    
            long begintime = System.nanoTime();
            /*int n = A.length;//简单递归
            System.out.println(sum1(A,n));*/
            int lo = 0;//二分递归
            int hi = A.length - 1;
            System.out.println(sum2(A, lo, hi));
            long endtime = System.nanoTime();
            long costTime = (endtime - begintime);
            System.out.println(costTime);
    
        }
    
        public int sum1(int A[], int n) {
            return (n < 1) ? 0 : sum1(A, n - 1) + A[n - 1];
        }
    

    分而治之

    public int sum2(int A[], int lo, int hi) {
            if (lo == hi) {
                return A[lo];
            }
            int mi = (lo + hi) >> 1;
            return sum2(A, lo, mi) + sum2(A, mi + 1, hi);
        }
    

    数组反向

    @Test
        public void test5() {
            int[] A = {100, 836, 3236, 5, 16, 26, -3, 89, 69, 43};
            int lo = 0;
            int hi = A.length - 1;
            reverse(A, lo, hi);
        }
    
        public void reverse(int[] A, int lo, int hi) {
            if (lo < hi) {
                int a = A[lo];
                A[lo] = A[hi];
                A[hi] = a;
                System.out.println(Arrays.toString(A));
                reverse(A, lo + 1, hi - 1);
            }
        }
    

    例子3:从数组区间中找出最大的两个整数元素

    @Test
        public void test6() {
            int[] A = {100, 836, 3236, 5, 16, 26, -3, 89, 69, 43};
            int lo = 0;
            int hi = A.length - 1;
            /*int[] int1 = max2(A, lo, hi);*/
            /*int[] int2 = max02(A, lo, hi);*/
            int[] int3 = max002(A, lo, hi);
    
            System.out.println(Arrays.toString(int3));
        }
    
        public int[] max2(int[] A, int lo, int hi) {
            int x1 = lo;
            int x2 = lo;
            //扫描lo-hi,找到x1
            for (int i = lo + 1; i < hi; i++) {
                if (A[x1] < A[i]) {
                    x1 = i;
                }
            }
            //扫描lo-x1,找到较大值
            for (int i = lo + 1; i < x1; i++) {
                if (A[x2] < A[i]) {
                    x2 = i;
                }
            }
            //扫描x1-hi,找到x2
            for (int i = x1 + 1; i < hi; i++) {
                if (A[x2] < A[i]) {
                    x2 = i;
                }
            }
            return new int[]{x1, x2};
        }
    

    改进1:

    public int[] max02(int[] A, int lo, int hi) {
            int x1 = lo;
            int x2 = lo + 1;
            if (A[x1] < A[x2]){
                int a = A[x1];
                A[x1] = A[x2];
                A[x2] = a;
            }
            for (int i = lo + 2;i < hi;i++){
                if (A[x2] < A[i]){
                    if (A[x1] < A[x2 = i]){
                        int a = A[x1];
                        A[x1] = A[x2];
                        A[x2] = a;
                    }
                }
            }
            return new int[]{x1, x2};
        }
    

    改进2:

    public int[] max002(int[] A, int lo, int hi) {
            int x1 = 0;
            int x2 = 0;
            if (lo + 1 == hi){
                if (A[x1 = lo] < A[x2 = hi]){
                    int a = x1;
                    x1 = x2;
                    x2 = a;
                }
                return new int[]{x1,x2};
            }
            if (lo + 2 == hi){
                int mid = (lo + hi)/2;
                if ((A[lo] > A[mid]) && (A[lo] > A[hi])){
                    x1 = lo;
                    x2 = (A[mid] > A[hi]) ? mid:hi;
                }else if((A[lo] < A[mid]) && (A[mid] > A[hi])){
                    x1 = mid;
                    x2 = (A[lo] > A[hi]) ? lo:hi;
                }else{
                    x1 = hi;
                    x2 = (A[lo] > A[mid]) ? lo:mid;
                }
                return new int[]{x1,x2};
            }
    
            int mi = (lo + hi) / 2;
            int[] L= max002(A, lo, mi);
            int[] R = max002(A, mi+1, hi);
    
            if (A[L[0]] > A[R[0]]){
                x1 = L[0];
                x2 = (A[L[1]] > A[R[0]]) ? L[1]:R[0];
            }else{
                x1 = R[0];
                x2 = (A[L[0]] > A[R[1]]) ? L[0]:R[1];
            }
            return new int[]{x1,x2};
        }
    

    相关链接

    例子3.5:最大综合区间(还没写)

    蛮力

    递增

    分治

    减治

    例子4:斐波那契数列

    动态规划

    @Test
        public void test7(){
            for (int i = 0;i < 25;i++){
    
                System.out.println(fib(i));
            }
        }
        public int fib(int n){
            int f = 0;
            int g = 1;
            while(0 < n--){
                g = g + f;
                f = g - f;
            }
            return g;
        }
    

    例子5:最长公共子序列

    情况分析


    @Test
        public void test8(){
            char[] x = {'A','B','C','B','D','A','B'};
            char[] y = {'B','D','C','A','B','A'};
            int[][] b = new int[x.length+1][y.length+1];
            int[][] c = lcsLength(x,y,b);
            System.out.println(c[x.length][y.length]);
            lcs(x.length,y.length,x,b);
        }
        //从[0][0]向[x.length+1][y.length+1]不断的得到1、共同序列个数 2、各种情况并作出标记
        public int[][] lcsLength(char[] x,char[] y,int[][] b) {
            //给第一行,第一列设置空序列
            int[][] c = new int[x.length+1][y.length+1]; //0存空序列
            for(int i=0;i<c.length;i++){
                for(int j=0;j<c[0].length;j++){
                    c[i][j] = 0;
                }
            }
            //进行规划
            for (int i = 1;i <= x.length;i++){
                for (int j = 1;j <= y.length;j++){
                    //情况一、末位相等,去除最后一个值并比较前面的(减而治之)
                    if (x[i-1] == y[j-1]){
                        c[i][j] = c[i-1][j-1]+1;
                        b[i][j] = 1;
                    }else{
                        //情况二、不相等,分别去除其中一个数列的末位并进行比较(分而治之)
                        if(c[i-1][j]>=c[i][j-1]){
                            c[i][j] = c[i-1][j];
                            b[i][j] = 2;
                        }else{
                            c[i][j] = c[i][j-1];
                            b[i][j] = 3;
                        }
                    }
                }
            }
            //返回规划好的情况c
            return c;
        }
        public void lcs(int i,int j,char[]x,int[][]b){
            //结束条件
            if (i==0 || j==0){
                return;
            }
            //判断b[i][j]进入不同分支
            if (b[i][j]==1){
                //减而治之
                lcs(i-1,j-1,x,b);
                System.out.print(x[i-1]);
            }else {
                //分而治之
                if (b[i][j] == 2){
                    lcs(i-1,j,x,b);
                }else{
                    lcs(i,j-1,x,b);
                }
            }
        }
    

    空间优化

    /**
         * 方法二、进行空间上的优化
         * 通过状态方程可知,计算c[i][j]时只需知道c[i-1][j-1]、c[i-1][j]、c[i][j-1]就行了
         * 那么就和斐波那契数列比较相似,可以利用滚动数组
         */
        //从[0][0]向[x.length+1][y.length+1]不断的得到1、共同序列个数 2、各种情况并作出标记
        public Set<Character> lcsLength2(char[] x, char[] y) {
            Set<Character> set = new HashSet<>();
            //给第一行,第一列设置空序列
            int[][] c = new int[x.length+1][y.length+1]; //0存空序列
            for(int i=0;i<c.length;i++){
                for(int j=0;j<c[0].length;j++){
                    c[i][j] = 0;
                }
            }
            //进行规划
            for (int i = 1;i <= x.length;i++){
                for (int j = 1;j <= y.length;j++){
                    //情况一、末位相等,去除最后一个值并比较前面的(减而治之)
                    if (x[i-1] == y[j-1]){
                        c[i%2][j] = c[(i-1)%2][j-1]+1;
                        char a = y[j-1];
                        set.add(a);
                    }else{
                        //情况二、不相等,分别去除其中一个数列的末位并进行比较(分而治之)
                        c[i%2][j] = Math.max(c[i%2][j-1],c[(i-1)%2][j]);
                    }
                }
            }
            //返回规划好的情况c
            return set;
        }
    

    递归版本(没写JAVA版的)

    function LCS(str1, str2, a, b) {
          if(a === void 0){
              a = str1.length - 1
          }
          if(b === void 0){
              b = str2.length - 1
          }
          if(a == -1 || b == -1){
              return 0
          } 
          if(str1[a] == str2[b]) {
             return LCS(str1, str2,  a-1, b-1)+1;
          }
          if(str1[a] != str2[b]) {
             var x =  LCS(str1, str2, a, b-1)
             var y =  LCS(str1, str2, a-1, b)
             return x >= y ? x : y
          }
      }
    

    相关链接

    例子6:就地循环位移(还没写)

    例子7:就地随机置乱(还没写)

  • 相关阅读:
    dom4j 创建XML文件
    Convert.ToInt32()与int.Parse()的区别
    委托
    工厂模式
    策略模式
    大型网站架构演化
    字符串反转(面试)
    switch(面试)
    带宽计算
    新语法
  • 原文地址:https://www.cnblogs.com/suit000001/p/13373802.html
Copyright © 2011-2022 走看看