数据结构(持续更新)

算法

  • 计算 = 信息处理
    借助某种工具,遵照一定规则,以明确而机械的形式进行
  • 所谓算法,即特定计算机模型下,旨在解决特定问题的指令序列
    • 输入 待处理的信息(问题)
    • 输出 经处理的信息(答案)
    • 正确性 的确可以解决指定的问题
    • 确定性 任一算法都可以描述为一个由基本操作组成的序列
    • 可行性 每一基本操作都可实现,切在常数时间内完成
    • 有穷性 对任何输入,经过又穷次基本操作都可以得到输出
序列Hailstone(n)   

好算法

  • 正确
  • 健壮
  • 可读
  • 效率 (速度尽可能快;存储空间尽可能少)
To measure is to know.
If you can not measure it,
you can not improve it.
- Lord Kelvin

算法分析

两个主要方面:

  1. 正确性;
  2. 成本:运行时间+所需空间

RAM:Random Access Machine

  • 寄存器顺序编号,总数没有限制(R[0],R[1]…)
  • 每一基本操作仅需常数时间
  • 与TM 模型一样看,RAM模型也是一般计算机的简化与抽象,使我们可以独立于具体的平台,对算法的效率做出可信的比较与评判
  • 在这些模型中 算法的运行时间+无穷大 算法需哟啊执行的基本操作次数 T(n) = 算法为求解规模为n的问题,所需执行的基本操作次数

大O记号

Mathematics is more in need
of good notations than 
of new theorems.
- Alan Turing
好读书不求甚解
每有会意,便欣然忘食
   -- 陶渊明

常数(constant function)
这类算法的效率最高
算法分析

He calculated just as men breathe
as eagles sustain themselves in the air.
- Francois Arago

两个主要任务

  1. 正确性
  2. 复杂度

复杂度分析的主要方法

  1. 迭代: 级数求和
  2. 递归:递归跟踪+地推放出
  3. 猜测+验证

级数

  • 算数级数:与末项平方同阶
  • 幂方级数:比幂次高出一阶
  • 几何级数:与末项同阶
  • 收敛级数: 常数
  • 调和级数:1+1/2+…+1/n=O(log n)
  • 对数级数:log1+log2+…+logn=O(log n)
相关书籍:Concrete Mathematics

起泡排序

//n 为在某个位置之前排序(不包含),相当于arr数组的长度
public void vuvvlesort(int[] arr,int n){
  for(boolean sorted = false; sorted = !sorted;  n--){
    for(int i = 1; i < n; i++){
      if(arr[i-1]>arr[i]){
        swap(arr,arr[i-1],arr[i]);//交换两个元素位置函数,需要自己实现
      }
    }
  }
}

封底估算(Back-Of-The-Envelope Calculation)

某位物理学家当时在测量原子弹爆炸威力时,在安全范围内将一张纸撕成很多个碎片,在爆炸时将手里的纸扔下,通过计算纸张落下的位置来 计算原子弹爆炸的威力,与当时计算机计算出来的数值仅仅差距为2倍,换算成O的算法,同阶!!! 

小思考:如果让你测量地球周长,如何进行呢?

迭代乃人工,递归方神通(To iterate is human,to recurse,divine.)
凡治众如治寡,分数是也(The control of a large force is the same principle as the control of a few men:it is merely a question of dividing up their numbers)

简而治之

分而治之

  • 二分递归
    数组求和:二分递归
sum(int[] arr,int lo,int hi){
  if(lo == hi)  return arr[lo];
  int mi = (lo + hi) >> 1;
  return sum(arr, lo, mi) + sum(arr, mi + 1, hi);
}
    public int[] max2(int[] arr, int lo, int hi){
        int[] result=new int[2];
        if (lo + 2 == hi) {
             return arr[lo] >= arr[lo+1] ? new int[]{ arr[lo], arr[lo + 1] } : new int[]{arr[lo + 1], arr[lo]};
        }
        if (lo + 3 == hi) {
            if (arr[lo] >= arr[lo + 1]) {
                return arr[lo + 1] > arr[lo + 2] ? new int[]{arr[lo], arr[lo + 1]} 
                                            : arr[lo] >= arr[lo + 2]  ? new int[]{arr[lo], arr[lo + 2]} : new int[]{arr[lo + 2], arr[lo]};
            } else {
                return arr[lo] > arr[lo + 2] ? new int[]{arr[lo+1], arr[lo]}
                                            : arr[lo + 1] >= arr[lo + 2] ? new int[]{arr[lo + 1], arr[lo + 2]}: new int[]{arr[lo + 2], arr[lo + 1]};
            }
        }
        int mi = (lo + hi) >> 1;
        int[] los = max2(arr, lo, mi);
        int[] his = max2(arr, mi, hi);
        if (los[0] >= his[0]) {
            return los[1] >= his[0] ? new int[]{los[0], los[1]} : new int[]{los[0], his[0]};
        } else {
            return his[1] >= los[0] ? new int[]{his[0], his[1]} : new int[]{his[0], los[0]};
        }
    }
    private void swap(int[] arr, int a, int b) {
        arr[a] = arr[a] ^ arr[b];
        arr[b] = arr[a] ^ arr[b];
        arr[a] = arr[a] ^ arr[b];
    }

动态规划

Make it work,
make it right,
make it fast.
- Kent Beck

思考计算:斐波那契数列

public int  f(int n){
  if(n == 0){
  	return 0;
  }else if(n == 1){
  	return 1;
  }
  return f(n - 1) + f(n - 2);
}

这个算法时间复杂度特别高,大概求50左右的数字会感觉到明显延迟,而且之后每多一个会呈现几何倍数增长,算法时间复杂度O(n^2)
改进:

public int f(int n){
  int f=0;
  int g=0;
  while(0 < n--){
    g += f;
    f = g - f;
  }
  return g;
}

子序列(Subsequence):
求两个字符串的最大公共子序列

等待更新...
递归版本(O(2^n))
动态规划版本(O(m*n)

向量

抽象数据类型&数据结构

  • 抽象数据类型:数据模型+定义在该模型上的一组操作
  • 数据结构:基于某种特定语言,实现ADT的一整套算法

linear array

  • 静态空间管理 -> 动态空间管理
    蝉的哲学:
    身体每经过一段时间的生长,以至无法为外壳容纳
    即蜕去原先的外壳,代之以…
  • 容量加倍策略
    Increment

分析方法:

  • 平均分析
  • 分摊分析

输入敏感(input-sensitive):最好和最坏复杂度相差悬殊
54

发布了7 篇原创文章 · 获赞 0 · 访问量 105

猜你喜欢

转载自blog.csdn.net/weixin_44188300/article/details/103744150