算法导论学习笔记(1)|Foundations

1. Getting Started

1.1 Insertion-Sort

Insertion Sort

public class InsertSort {
    private static ArrayList array = new ArrayList<>();

    private static void insertSort(ArrayList array) {
        System.out.println(array);
        for(int i = 1; i < array.size(); i ++) {
            int value = array.get(i);
            int j = i - 1; // 对i左边的部分进行循环
            while(j >= 0 && array.get(j) > value) {
                array.set(j + 1, array.get(j)); //如果j位置上的数值大于value,则把j位置上的数向右移动一个
                j = j - 1; // 继续向左
            }
            array.set(j + 1, value); // 跳出循环所得到的数j就是待插入位置左边的位置

        }
        System.out.println(array);
    }

    public static void main(String[] args) {
        array.add(4);
        array.add(5);
        array.add(4);
        array.add(3);
        array.add(2);
        insertSort(array);
    }
}

1.2 Loop Invariants

如果一个算法要实现正确性,则其必须满足循环不变性
Initialization: 第一次循环必须正确
Maintenance: 如果第一次循环前是正确的,那么下一次循环也保持正确
Termination: 当循环结束的时候,结果是正确的

1.3 Pseudocode Conventions

  • 缩进就是块结构
  • 循环结构 while, for, and repeat-until 和条件结构 if-else
  • 符号 “//” 意味着注释
  • i = j = e 表示ij同时赋值 e
  • 没有特殊声明的话,所有的变量都是局部变量
  • A[i]这种形式来表示访问数组A的第i个元素
  • objects.attr这种形式访问对象的属性
  • 以传值的方式传参
  • return语句立即返回,不带任何值
  • error关键字代表因为条件错误导致的错误发生

1.4 Analyzing algorithms

  • 输入大小:不同的问题有不同的描述方式,可以是一个输入数组中元素的个数,也可以是点和边共同组成
  • 运行时间:基础运算符和步骤的数量
  • Order of Growth

Selection Sort

import java.util.ArrayList;

public class SelectionSort {
    public static void selectionSort(ArrayList array) {
        // 1. find the biggest element in the unsortedArray
        // 2. exchange it with A[i]
        for(int i = 0; i < array.size(); i ++) {
            int max_v = array.get(i);
            int max_v_index = i;
            for(int j = i; j < array.size(); j ++) {
                if(array.get(j) > max_v) {
                    max_v = array.get(j);
                    max_v_index = j;
                }
            }
            int temp = array.get(i);
            array.set(i, max_v);
            array.set(max_v_index, temp);
        }
        System.out.println(array);
    }


    public static void main(String[] args) {
        ArrayList array = new ArrayList<>();
        array.add(4);
        array.add(5);
        array.add(4);
        array.add(3);
        array.add(2);
        selectionSort(array);
    }
}

2. Designing algorithms

  • Incremental Approach
  • Divide and Conquer: Divide the problem into subproblems and conquer them straightforward

2.1 Merge Sort

public class MergeSort {
    private static List mergeSort(List arrayList) {
        if(arrayList.size() == 1) {
            return arrayList;
        }
        // 1. divide the problem into sub-problems
        List leftArray =  arrayList.subList(0, arrayList.size() / 2);
        List rightArray = arrayList.subList(arrayList.size() / 2, arrayList.size());
        // 2. conquer them respectively
        leftArray = mergeSort(leftArray);
        rightArray = mergeSort(rightArray);
        // 3. merge the sub-array into a completed one

        return merge(leftArray, rightArray);

    }

    private static List merge(List leftArray, List rightArray) {
        ArrayList arrayList = new ArrayList<>();
        int leftArrayIndex = 0;
        int rightArrayIndex = 0;
        while(leftArray.subList(leftArrayIndex, leftArray.size()).size() > 0 && rightArray.subList(rightArrayIndex, rightArray.size()).size() > 0) {
            if(leftArray.get(leftArrayIndex) > rightArray.get(rightArrayIndex)) {
                arrayList.add(leftArray.get(leftArrayIndex));
                System.out.println("加入" + leftArray.get(leftArrayIndex) + "之后" + arrayList);
                leftArrayIndex ++;
            } else {
                arrayList.add(rightArray.get(rightArrayIndex));
                System.out.println("加入" + rightArray.get(rightArrayIndex) + "之后" + arrayList);
                rightArrayIndex ++;
            }
        }
        if(leftArray.size() > 0) {
            arrayList.addAll(leftArray.subList(leftArrayIndex, leftArray.size()));
        }
        if(rightArray.size() > 0) {
            arrayList.addAll(rightArray.subList(rightArrayIndex, rightArray.size()));
        }
        System.out.println(arrayList);
        return arrayList;
    }

    public static void main(String[] args) {
        ArrayList array = new ArrayList<>();
        array.add(1);
        array.add(5);
        array.add(4);
        array.add(3);
        array.add(2);
        mergeSort(array);

    }
}

2.2 Analysis of Divide and Conquer Algorithm

  • a: sub-problem的数量
  • b: 原来问题与sub-problem大小的比值

课后练习2.3 -4

public class RecurrenceInsertionSort {

    private static List array;

    private static void recurrenceInsertionSort(List arrayList, int n) {
       if(n == 0) {
           return;
       } // n指向当前处理的元素的索引,当为0的时候就退出,即不处理指向第一个数的那一轮
       recurrenceInsertionSort(arrayList, n - 1); // 建立递归树

       int i = n - 1;  // 
       int key = (int)arrayList.get(n);//当前元素
        // 当当前元素前的元素大于当前元素,那么把它们都移动位置,直到没有大于当前元素,那么也就保存了应该插入的位置i
       while(i > 0 && (int)arrayList.get(i) > key) {
           arrayList.set(i + 1, arrayList.get(i));
           i --;
       }
       //把key(当前元素)插入合适的位置
       arrayList.set(i + 1, key);

    }
    public static void main(String[] args) {
        array = new ArrayList<>();
        array.add(1);
        array.add(5);
        array.add(7);
        array.add(3);
        array.add(2);
        recurrenceInsertionSort(array, 4);
        for(Object o : array) {
            System.out.println(o);
        }
    }
}

课后练习2.3 -5

public class BinarySearch {
    private static boolean binarySearch(List arrayList, int value) {
        int mid_index = arrayList.size() / 2;
        int mid_value = arrayList.get(mid_index);
        if(value == mid_value) {
            System.out.println("找到了" + value + arrayList);
            return true;
        }
        // 1. compare
        if(value < mid_value) {
            if(arrayList.size() == 1 && arrayList.get(0) != value) {
                return false;
            }
            return binarySearch(arrayList.subList(0, mid_index), value);
        } else {
            if(arrayList.size() == 1 && arrayList.get(0) != value) {
                return false;
        }
            return binarySearch(arrayList.subList(mid_index, arrayList.size()), value);
        }
    }
    public static void main(String[] args) {
        List array = new ArrayList();
        array.add(1);
        array.add(2);
        array.add(4);
        array.add(6);
        array.add(7);
        System.out.println(binarySearch(array, 3));
    }
}

3. Growth Of Functions

3.1


  • g(n) is an asymptotically tight bound for f(n)
  • f(n) is asymptotically nonnegative

3.2

  • asymptotic upper bound
  • 表示存在一个的上界

3.3

  • asymptotic lower bound

3.4 Theorem 1

For any two functions and , we have = only if and

3.5

3.6

3.7 Comparing Functions

3.7.1 Transitivity

3.7.2 Reflexivity

3.7.3 Symmertry

3.7.4 Transpose Symmetry

3.8 Standard Notations and Common Functions

  • Monotonicity
  • Floors and Ceilings
  • Modular Arithmetic
  • Polynomials
  • Exponentials
  • Logarithms
  • Factorials
  • Functional Iteration
  • Fibonacci numbers

4. Divide-and-Conquer

recursive case
base case
有时会处理与原问题类型不同的问题,把这些问题放在conquer步骤中解决

4.1 Find Maximum Subarray

import java.util.ArrayList;
import java.util.List;

public class FindMaximumSubArray {
    private static List findMaximumSubArray(List array, int low, int high) {
        if(low == high) {
            ArrayList arrayList = new ArrayList<>();
            arrayList.add(low);
            arrayList.add(high);
            arrayList.add(array.get(low));
            return arrayList;
        } else {
            int mid = (low + high) /2;
            
            List leftArrayList = findMaximumSubArray(array, 0, mid);
            int leftSum = leftArrayList.get(2);
            
            List rightArrayList = findMaximumSubArray(array, mid + 1, high);
            int rightSum = rightArrayList.get(2);
            
            List crossArrayList = findMaximumCrossingArray(array, low, mid, high);
            int crossSum = crossArrayList.get(2);

            if(leftSum >= leftSum + rightSum && leftSum + rightSum >= crossSum) {
                return leftArrayList;
            } else if(rightSum >= rightSum + leftSum && rightSum + leftSum >= crossSum) {
                return rightArrayList;
            } else {
                return crossArrayList;
            }
        }
    }

    private static List findMaximumCrossingArray(List array, int low, int mid, int high) {
        int leftSum = 0;
        int sum = 0;
        int leftIndex = 0;
        int rightIndex = 0;

        List retList = new ArrayList<>();
        for(int i = mid; i >= low; i --) {
            sum += array.get(i);
            if(sum > leftSum) {
                leftSum = sum;
                leftIndex = i;
            }
        }

        int rightSum = 0;
        sum = 0;

        for(int j = mid + 1; j <= high; j ++) {
            sum += array.get(j);
            if(sum > rightSum) {
                rightSum = sum;
                rightIndex = j;
            }
        }
        retList.add(leftIndex);
        retList.add(rightIndex);
        retList.add(leftSum + rightSum);
        return retList;
    }

    public static void main(String[] args) {
        List array = new ArrayList<>();
        array.add(1);
        array.add(5);
        array.add(-7);
        array.add(3);
        array.add(5);
        array.add(-2);
        array.add(-9);
        array.add(4);
        System.out.println(findMaximumSubArray(array, 0, 7));
    }
}

5. 求解递归式

5.1 Substitution Method

5.1.1 The Substitution Method for Solving Recurrences

证明的时候需要

  1. 假设一个可能的解
  2. 带入证明成立
  3. 如果在2中遇到了一些边界值,需要证明存在性就行

本质上数学归纳法,需要证明base caseInductive case
康奈尔大学笔记:Using the substituion and master methods

5.1.2 Making a Good Guess

  • If a recurrence is similar to one you have seen before, then guessing a similar
    solution is reasonable
  • prove loose upper and lower bounds onthe recurrence and then reduce the range of uncertainty

5.2 The Recursion-tree method

  • 用Recursion-tree method生成可能解,然后用代入法来验证

分治法 ( Divide And Conquer ) 详解

5.3 The Master Method

  • 1和2,2和3之间都有gap
  • Master Method不能涵盖所有的情况

6. Probabilistic Analysis and Randomized Algorithms

Probabilistic analysis
最好/最坏/平均分析:由于输入的分布不同,因此产生了这三种情况

randomized algorithm:算法表现不仅仅依赖于输入,还依赖于随机数生成

6.1 Indicator Random Variables

  • 帮助概率与期望之间的转换

6.1 Randomized Algorithm

Lemma3
The expected hiring cost of the procedure RANDOMIZED-HIRE-ASSISTANT is

  • 随机化算法将输入的序列重新排列,使得算法不依靠输入序列的分布,让每一种分布都有可能

6.2 随机序列生成算法

1. 算法一:生成优先级

2. 算法二:随即交换

你可能感兴趣的:(算法导论学习笔记(1)|Foundations)