Data structure and algorithm

Data structure and algorithm 2020 notes

1, Linear structure and nonlinear structure

1.1 linear structure (9.17)

Common linear structures: array, queue, linked list, stack

Sequential storage structure (array) and chain storage structure, one-to-one linear relationship

One-to-one array structure, non-linear array structure, non-linear tree structure

1.2 sparse array

When most elements in an array are 0 or an array with the same value, sparse array can be used to save the array

Treatment method:

  • How many rows and columns are there in the record array? How many different values are there
  • Record the rows, columns and values of elements with different values in a small-scale array, so as to reduce the size of the program (compression)
  • Used to preserve two-dimensional arrays (chessboard, map, etc.)

1.3 queue

  • Ordered list (array, linked list)
  • First in first out
1.3.1 array simulation queue

Disadvantages: cannot be reused

1.3.2 array simulation ring queue
  • Conditions for queue full: (rear + 1)% maxSize = front
  • Queue is empty: rear == front
  • Initial value: front == rear == 0
  • Number of valid data in the queue: (rear + maxSize - front)% maxSize (common small algorithm)

1.4 linked list

  1. Linked list is stored in the form of nodes, chain storage
  2. Each node contains the data field, and the next field: points to the next node
  3. The nodes of the linked list are not necessarily stored continuously
  4. Lead node and headless node. The head node does not store any data and is used to find the linked list entry
//Creation of one-way linked list 
private HeroNode head = new HeroNode(0, "");  

//Join last
public void add(HeroNode heroNode) {
    HeroNode temp = head;
    while (true) {
        if (temp.next == null) {
            break;
        }
        //If the last is not found, move temp back
        temp = temp.next;
    }
    temp.next = heroNode;
    
}

//Display linked list (traversal)
public void list(){
    if (head.next == null) {
        return ;
    }
    
    //The head node cannot be moved and needs an auxiliary variable to traverse
    HeroNode temp = head.next;
    while (true) {
        if (temp == null){
            break;
        }
        //syso node
        //Move the temp backward and be careful of the dead cycle
        temp = temp.next;
    }
}

class HeroNode {
    public int no;
    public String name;
    public HeroNode next;
}

/*
Add in order: new nodes next = temp.next; temp.next = new node;
*/
public void addByOrder(HeroNode heroNode){
    //Single linked list: the temp to be found is the previous node of the addition location, otherwise it cannot be added
    HeroNode temp = head;
    boolean flag = false; // Judge whether the added number exists
    while (true) {
        if (temp.next == null) {
            break;
        }
        if (temp.next.no > heroNode.no) {
            break;
        } else if (temp.next.no == heroNode.no) {
            flag = true;
            break;
        }
        temp = temp.next; // Move back and traverse the current linked list
    }
    
    //Judge the value of flag
    if (flag) {
        //syso exists and cannot be added
    } else {
        heroNode.next = temp.next;
        temp.next = heroNode;
    }
}

Modify node \ delete node

public void update(HeroNode heroNode) {
    if (head.next == null) {
        return;
    }
    
    HeroNode temp = new HeroNode();
    temp = head;
    while (heroNode.no != temp.next.no && temp.next != null) {
        update();
        temp = temp.next;
    }
    
    if (temp.next == null) return;
    else update();
}
1.4.1 bidirectional linked list
  • One way linked list can only be traversed and searched from one direction
  • A one-way linked list cannot be deleted by itself and needs to rely on auxiliary nodes, while a two-way linked list can be deleted by itself. When a single linked list deletes a node, you should find temp, which is the previous node of the node to be deleted.
1.5.2 one way circular linked list & Joseph problem

Joseph's problem: let n people with numbers 1, 2,..., n sit around. It is agreed that the person with number k (1 < = k < = n) will count from 1, the person who counts to m will be listed, his next person will start counting, and so on until everyone is listed, resulting in a sequence of out of line numbers.

Solution: circular linked list, array module

public class Josepfu {
    public static void main(String[] args){
        
    }
}

class CircleSingleLinkedList{
    //first node
    private Boy first = new Boy(-1);
    
    public void addBoy(int nums) {
        if (nums < 1) {
            return;
        }
        //Use the for loop to create a circular linked list
        Boy curBoy = null;
        for (int i = 1; i <= nums; i++){
            //According to the number, create a child node and an auxiliary node cur
            Boy boy = new Boy(i);
            if (i == 1) {
                first = boy;
                first.setNext(first);//Constituent ring
                curBoy = first;
            } else {
                
            }
        }
    }
}

//Traverse circular linked list
public void showEle() {
    if (first == null) {
        return;
    }
    
    Boy cur = first;
    while (true) {
        //syso show cur.no
        cur = cur.getNext();
        if (cur == first) break;
    }
}

class Boy{
    private int no ;
    private Boy next;
    
}

Loop out analysis of ring linked list:

  1. You need to create an auxiliary variable helper to point to the last node of the ring linked list in advance (while loop traversal points to the last node)
  2. Before counting off, let the first and helper move k-1 times to the location of the K node
  3. When counting, let the first and helper move m-1 times at the same time
  4. At this time, circle the child node pointed to by first. First = first next helper. next = first

2, Stack

2.1 introduction to stack

  • Ordered list of first in first out
  • The top of the stack is the changing end, the insertion and deletion operations, and the bottom of the stack is the fixed end
  • Out of stack pop
  • Stack push

2.2 application scenarios

  1. Subroutine calling, processing and recursive calling
  2. Conversion and evaluation of expressions
  3. Traversal of binary tree
  4. Depth first search of graphics

2.3 use of array simulation stack

Train of thought analysis:

  1. Define a top to represent the top of the stack, which is initialized to - 1,
  2. Stack operation: Top + +; stack[top] = value;
  3. Stack out operation: int value = stack[top]; top–; return value;
  4. When traversing, the data is displayed from the top of the stack
//Judge whether the stack is empty and exit the stack
public int pop() { 
    if (isEmpty()) {
        throw new RuntimeException("Stack empty, no data");
    }
    int value = stack[top];
    top--;
    return value;
}

2.4 simulate stack with linked list (null)

3, Prefix, infix, suffix expression

3.1 prefix expression (Polish expression)

  1. The operator of the prefix expression precedes the operand
  2. The prefix expression corresponding to (3 + 4) * 5 - 6 is - * + 3 4 5 6
  3. Computer evaluation method: scan the expression from right to left. When encountering a number, push the number into the stack. When encountering an operator, pop up the two numbers at the top of the stack, use the operator to calculate the corresponding (top element and secondary top element), and put the result into the stack. Repeat the above process until the leftmost end of the expression. The final value is the result of the expression.
  4. For the above expression, press 6 5 4 3 from right to left, get 7 when encountering + pop 3 4, and then enter the stack when encountering * pop 7 * 5 = 35, 35... At this time, 35 is at the top of the stack

3.2 infix expression

  1. Is a common operation expression
  2. However, it is not easy for computers to operate (because infix expressions need to judge the priority of operators and the priority of subsequent operators). When calculating the results, infix expressions are often converted into other expressions (generally suffix expressions)

3.3 suffix expression

  1. Also known as inverse Polish expression
  2. Similar to the prefix, except that the operator follows the operand
  3. (3 + 4) * 5-6: suffix expression: 3 4 + 5 * 6 - 35 is under 6
  4. 4 * 5 - 8 + 60 + 8 / 2 ------------------- 4 5 * 8 - 60 + 8 2 / +

3.4 inverse Polish calculator (partial code)

//Put the inverse Polish expression, and put the data and operators in sequence, such as 3, 4 + 5 * 6 in ArrayList-
public static List<String> getListString(String str){
    String[] split = str.split(" ");
    List<String> List = new ArrayList<String>();
    for (String ele : split) {
        list.add(ele);
    }
    return list;
}

//calculation
public static int calculate(List<String> ls){
    Stack<String> stack = new Stack<String>();
    
    for (String item : ls) {
        if (item.matches("\\d+")) {
            //Push 
            stack.push(item);
        } else {
            //pop out two numbers, operate them, and then put them on the stack
            int num2 = Integer.parseInt(stack.pop());
            int num1 = Integer.parseInt(stack.pop());
            int res = 0;
            if (item.equals("+")){
                res = num1 + num2;
            } else if (item.equals("-")){
                res = num1 - num2;
            } else if (item.equals("*")){
                res = num1 * num2;
            } else if (item.equals("/")){
                res = num1 /num2;
            } else {
                throw new Exception("error");
            }
            stack.push(res + "");
        }
        
        
    }
    return Integer.parseInt(stack.pop());
}

3.5 thinking analysis of infix to suffix expression (9.20)

code:

//Infix expression is converted to the corresponding list, and then infix expression is converted to suffix expression
public static List<String> toInfixExpressionList(String s) {
    List<String> ls = new ArrayList<String>();
    
    int i = 0;
    String str;
    char c;
    
    do {
        if ((c = s.charAt(i)) < 48 || (c = s.charAt(i)) > 57) {
            ls.add("" + c);
            i++;
        } else {
            //If it is a number, multiple numbers need to be considered
            str = "";//First set str to "" '0' [48] - > '9' [57]
            while (i < s.length() && (c = s.charAt(i)) >= 48 && (c = s.charAt(i)) <= 57) {
                str += c;
                i++;
            }
            ls.add(str);
        }
    } while (i < s.length());
    return ls;
}

//Infix to suffix
public static List<String> parseSuffixExpressionList(List<String> ls){
    //Define two stacks
    Stack<String> s1 = new Stack<String>(); //Symbol stack
    
    //Because s2 stack has no pop operation in the whole conversion process, and it needs to be output in reverse order, so list is used
    //Stack<String> s2 = new Stack<String>();
    List<String> s2 = new ArrayList<String>(); // list2 for storing intermediate results
    
    //Traversal ls
    for (String item : ls) {
        //If it's a number, add s2
        if (item.matches("\\d+")) {
            s2.add(item);
        } else if (item.equals("(")) {
            s1.push(item);
        } else if (item.equals(")")) {
            while (!s1.peek().equals("(")){
                s2.add(s1.pop());
            }
            s1.pop(); //Pop up(
        } else {
            while (s1.size() != 0 && Operation.getValue(s1.peek()) >= Operation.getValue(item)) {
                s2.add(s1.pop());
            }
            s1.push(item);
        }
    }
    
    //Pop the operators in the remaining s1 into s2 in turn
    while (s1.size() != 0) {
        s2.add(s1.pop());
    }
    
    return s2;
    
} 

//Writing an Operation class can return the priority corresponding to an operator
class Operation{
    private static int ADD = 1;
    private static int SUB = 1;
    private static int MUL = 2;
    private static int DIV = 2;
    
    public static int getValue(String operation){
        int result = 0;
        switch (operation) {
            case "+" :
                result = ADD;
                break;
            case "-" :
                result = SUB;
                break;
            case "*" :
                result = MUL;
                break;
            case "/" :
                result = DIV;
                break;
            default :
                //syso : not exsist;
                break;
        }
        return result;
    }
}

4, Recursion

4.1 application scenario & problem solving

recursion: maze problem (backtracking), printing problem, factorial problem

Problem solving: eight queens problem, Hanoi Tower, factorial, maze, ball and basket, fast row, merge sort, binary search, divide and conquer algorithm, shortest path, minimum spanning tree, problems solved by stack, etc

Call rule:

  1. When the program executes a method, it will open up an independent space (stack)
  2. The local variables of the method are independent and will not affect each other
  3. Reference type variables (in the stack) will share data (such as arrays)
  4. return end method

4.2 maze problem

4.3 eight queens problem

A typical case of backtracking algorithm: eight queens are placed on an 8 * 8 grid chess. Any two queens cannot be in the same row, column, or slash. Ask how many pendulum methods there are.

92 species

4.3.1 array solution

The number of backtracking reaches 1w5, which is relatively large

//Write a method to place the n th queen
private void check(int n) {
    if (n == max) {//max = 8
        print();
        return;
    }
    
    for (int i = 0; i < max; i++) {
        //First, put the current queen n in the first column of the row
        array[n] = i;
        //Judge whether there is a conflict when the nth queen is currently placed in column i
        if (judge(n)) {
            //No conflict, then put n+1 queens and start recursion
            check(n+1); //
        }
        //If there is a conflict, continue to execute array[n] = i; That is, the nth queen is placed in the backward position of the line
        
    }
}


//Judge whether the placed queen conflicts with the position in front
private boolean judge(int n) {
    for (int i =  0; i < n; i ++) { // Growth by line
        // 1.array[i] == array[n] means to judge whether the nth queen is in the same column as the previous queen
        // 2.Math.abs(n-i) == Math.abs(array[n] - array[i]) determines whether the nth queen is on the same slash as the ith queen
        if (array[i] == array[n] || Math.abs(n-i) == Math.abs(array[n] - array[i])) {
             return false;
        }
    }
    return true;
}


5, Sorting algorithm

5.1 classification of sorting

  1. Internal sorting (all sorting operations are completed in memory)
    : load all data to be processed into internal memory for sorting
    : insert sort (direct insert sort, Hill sort), select sort (simple select sort, heap sort), exchange sort (bubble sort, quick sort)
    , merge sort, cardinal sort
  2. External sorting method (put data on disk and sort through disk and memory transmission)

5.2 time complexity

Ex post statistical method and ex ante estimation method

5.2.1 time and frequency

The number of statements executed in an algorithm is called statement frequency or time frequency, which is recorded as T(n)

  1. Ignore constant term: T(n) = 2n = 2n + 10
  2. Ignore the lower order: T(n^2) = n^2 + 5n + 10 = 3n ^2, perform curve coincidence
  3. The coefficients of higher-order terms can be ignored. n^3+5n and 6n^3 + 4n, perform curve separation, and explain how much power is the key
5.2.2 calculation of time complexity

5.2.3 common time complexity
  1. Constant order O(1): no matter how many lines of code are executed, as long as there is no complex structure such as loop, the time complexity of this code is O(1); (code execution does not increase with the growth of a variable)
  2. O(logN):
  3. Linear order O(n):
  4. Linear order (nlogo):
  5. ...
5.2.4 average time complexity and worst time complexity

5.2.5 space complexity

A measure of the amount of storage space temporarily occupied by an algorithm during operation. The essence of some cache products and algorithms (cardinality sorting, fast sorting and merging) is to trade space for time.

5.3 bubble sorting (9.21)

  1. A total of - 1 cycles of array size are carried out, and the maximum number is ranked last in each sorting
  2. The number of sortings per trip is gradually decreasing
  3. If there is no exchange in a certain sort, the bubble sort can be ended in advance. (optimized)
//O(n^2)
public void BubbleSort(int[] arr){
    int temp = 0;
    boolean flag = false;//Identify variables and whether they have been exchanged for simple optimization
    
    for (int i = arr.length - 1; i >= 0; i--){
        for (int j = 0; j < i; j++){
            if (arr[j] > arr[j + 1]) {
                flag = true;
                temp = arr[j + 1];
                arr[j + 1] = arr[j];
                arr[j] = temp;
            }
        }
        
        if(!flag){
            break;
        } else {
            flag = false;
        }
    }
    
    //for (int i = 0; i < arr.length-1; i++) 
    //  for (int j = 0; j < arr.length - 1 - i; j++){}
}


5.4 selection and sorting

Select the value of the specified size, put it into the specified position according to certain rules, and get the sequence from small to large by traversing n-1 times

First simple and then complex, the complex algorithm is divided into simple problems and then integrated

//Faster than bubble sorting in time
public static void selectSort(int[] arr) {
   
    for (int i = 0; i < arr.length -1; i++){
        int minIndex = i;
        int min = arr[i];
        for (int j = i; j < arr.length - 1; j++){
            if (arr[j] < min) {
                minIndex = j;
                min = arr[j];
            }
        }
        
        if (minIndex != i){
            arr[minIndex] = arr[i];
        	arr[i] = min;
        }
        
    }
}

5.5 insert sort

Basic idea: regard the n elements to be sorted as an ordered table and an unordered table, take out the first element from the unordered table each time, and insert it into the appropriate position of the ordered table.

public static void InsertSort(int[] arr){
    for (int i = 1; i < arr.length; i++){
        int insertVal = arr[i];
        int insertIndex = i - 1; //The number to be inserted into the unordered list is compared with the previous subscript
        
        //Find the insertion position for insertVal
        /*
        1.insertVal >= 0, Prevent cross-border
        2.insertVal < arr[insertIndex] compare
        3.arr[insertIndex] Move back
        */
        while (insertIndex >= 0 && insertVal < arr[insertIndex]) {
            arr[insertIndex + 1] = arr[insertIndex];
            insertIndex--;
        }
        //if (insertIndex+1 == i)
        arr[insertIndex + 1] = insertVal;
        
    }
}

5.6 Hill sorting

Possible problems with simple insertion sorting:

When the number of inserts is small, the number of backward moves increases significantly, and the efficiency will be affected

Hill sorting introduction: reduce incremental sorting and insert an efficient version of sorting

Basic idea: group according to a certain increment of subscript, and use insertion sorting for each group. As the increment decreases, it decreases to 1

5.6.1 exchange method
public static void shellSort(int[] arr){
    
    for (int gap = arr.length / 2; gap > 0; gap /= 2) {
        for (int i = gap; i < arr.length; i++){
            //Traverse all elements in each group (a total of gap groups, each group has), step gap
            for (int j = i - gap; j >= 0; j -= gap) {
                if (arr[j] > arr[j + gap]){
                    temp = arr[j];
                    arr[j] = arr[j + gap];
                    arr[j + gap] = temp;
                }
            }
        }
    }
    
    
    //Low efficiency
}
5.6.2 displacement method
//nlogn - n ^ (1~2)
//Optimize the Hill sort of exchange 
public static void shellSort2(int[] arr) {
    
    //Incremental gap
    for (int gap = arr.length / 2; gap > 0; gap /= 2) {
        for (int i = gap; i < arr.length; i++){
            int j = i;
            int temp = arr[j];
            if (arr[j] < arr[j - gap]){
                while (j - gap >= 0 && temp < arr[j - gap]) {
                    //move
                    arr[j] = arr[j - gap];
                    j -= gap;
                }
                //After exiting the while loop, explain to find the insertion location for temp
                arr[j] = temp;
            }
        }
    }
        
}

5.7 quick sort

Basic idea: an improvement of bubble sorting. Through one-time sorting, the data to be sorted is divided into two independent parts. All the data in one part is smaller than all the data in the other part, and then the two parts are sorted quickly, which can be carried out in the same recursive way, so as to make the whole data orderly.

Code implementation:

//Recursive implementation of nlogn - n^2 recursion uses the stack to open up space and change space for time
public static void quickSort(int[] arr, int left, int right) {
    int l = left;
    int r = right;
    //Central axis value
    int pivot = arr[(left + right) / 2];
    int temp = 0;
    //The purpose of the while loop is to put those smaller than the pivot value on the left and those larger on the right
    while ( l < r ){
        //Keep looking on the left of pivot
        while (arr[l] < pivot) {
            l += 1;
        }
        while (arr[r] > pivot) {
            r -= 1;
        }
        if (l >= r) {
            break;
        }
        
        //exchange
        temp = arr[l];
        arr[l] = arr[r];
        arr[r] = temp;
        
        //If after the exchange, it is found that arr [l] = = the value of pivot, equal r --, move forward and reach the median value, stop the cycle
        if (arr[l] == pivot) r -= 1;
        
        if (arr[r] == pivot) l += 1;
    }
    
    //If l == r, it must be L + +, r --, otherwise the stack overflows
    if (l == r) {
        l+= 1;
        r-= 1;
    }
    
    if (left < r) quickSort(arr, left, r);
    
    if (right > l) quickSort(arr, l, right);
}

5.8 merge sort

Merge sort, using divide and conquer strategy

Rule: merge two ordered subsequences into one ordered sequence,

mergeSort: O(nlogN)

public static void mergeSort(int[] arr, int left, int mid, int right, int[] temp) {
    if (left < right) {
        int mid = (left + right) / 2;
        //Decompose recursively to the left
        mergeSort(arr, left, mid, temp);
        //right
        mergeSort(arr, mid + 1, right, temp);
        
        // To merge
        merge(arr, left, mid, right, temp);
    }
}


public static void merge(int[] arr, int left, int mid, int right, int[] temp){
    int i = left;
    int j = mid + 1;
    int t = 0; // Current index to temp
    
    //First fill the left and right (ordered) data into the temp array until one side is processed
    while (i <= mid && j <= right) {
        if (arr[i]  <= arr[j]){
            temp[t] = arr[i];
            t += 1;
            i += 1;
        } else {
            temp[t] = arr[j];
            t += 1;
            j += 1;
        }
    }
    //Fill remaining
    while (i <= mid) {
        //Left remaining
        temp[t] = arr[i];
        t+=1;
        i+=1;
    } 
    
    while (j <= right){
        temp[t] = arr[j];
        t+=1;
        j+=1;
    }
    //Copy the elements of temp array to arr
    t = 0;
    int tempLeft = left;
    while (tempLeft <= right) {
        // Merge 0, 1, 2, 3, 0, 3 for the first time.
        arr[tempLeft] = temp[t];
        t += 1;
        tempLeft += 1;
    }
}

5.9 cardinality sorting (bucket sorting extension)

  1. The elements to be sorted are assigned to some buckets by the value of each bit of the key value
  2. Cardinality sorting is an extension of bucket sorting
  3. Invented by Herman hollery in 1887: the integer is cut into different numbers according to the number of digits, and then compared according to each digit
  4. Stability ranking: 3 1 4 1 "1 1 3 4, the first 1 is still in the front
  5. Basic idea: unify all the values to be compared into the same digit length, fill zero in front of the number with shorter digits, and then sort them successively from the lowest bit.

public static void radixSort(int[] arr) { 
    
    //Define a two-dimensional array, representing 10 buckets, and each bucket is a one-dimensional array
    //Cardinality sorting: the classical operation of space for time
    int[][] bucket = new int[10][arr.length];
    
    //In order to record how many data are actually stored in each bucket, a one-dimensional array is defined to record the number of data put in each bucket
    //For example, bucketElementCounts[0] records the number of data put into the bucket[0]
    int[] bucketElementCounts = new int[10];
    
    //The first round of sorting is to sort the bits of each element
    for (int j = 0; j < arr.length; j++) {
        //Take out the single digit of each element
        int digitOfElement = arr[j] / 1 % 10;
        
        //Put it into the corresponding bucket
        bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[j];
        bucketElementCounts[digitOfElement]++;
        
    }
    
    //According to the order of this bucket (the subscript of one-dimensional array takes out the data in turn and puts it into the original array)
    int index = 0;
    //Traverse each bucket and put the data in the bucket into the original array
    for (int k = 0; k < bucketElementCounts.length; k++){
        //Judge whether there is data in the bucket
        if (bucketElementCounts[k] != 0) {
            //
            for (int l = 0; l < bucketElementCounts[k]; l++){
                arr[index++] = bucket[k][l]; //++
            }
        }
        //After the first round of processing, bucketelementcounts [k] = 0, the bucket array needs to be emptied
        bucketElementCounts[k] = 0;
    }
    
    //***********First round*************************
    //The second round: take ten arr[j] / 10% 10; 748 / 10 > 74 % 10 > 4
    
}


public static void radixSort2(int[] arr) {
    //Final code
    
    //1. Get the maximum number of digits in the array
    int max = arr[0];
    for (int i = 1; i < arr.length; i++) {
        if (arr[i] > max) {
            max = arr[i];
        }
    }
    int[][] bucket = new int[10][arr.length];
    
    
    //What is the maximum number
    int maxLength = (max + "").length();
    int[] bucketElementCounts = new int[10];
    
    for (int i = 0, n = 1; i < maxLength; i++, n *= 10){
     //Sort the corresponding bits of each element, including single bit, ten bit

    	for (int j = 0; j < arr.length; j++) {
        
        	int digitOfElement = arr[j] / n % 10; //** n **
        
        //Put it into the corresponding bucket
        	bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[j];
        	bucketElementCounts[digitOfElement]++;
        
    	}
    
    //According to the order of this bucket (the subscript of one-dimensional array takes out the data in turn and puts it into the original array)
    int index = 0;
    //Traverse each bucket and put the data in the bucket into the original array
    	for (int k = 0; k < bucketElementCounts.length; k++){
        //Judge whether there is data in the bucket
        	if (bucketElementCounts[k] != 0) {
            //
            	for (int l = 0; l < bucketElementCounts[k]; l++){
                	arr[index++] = bucket[k][l]; //++
            	}
        	}
        //After the first round of processing, bucketelementcounts [k] = 0, the bucket array needs to be emptied
        	bucketElementCounts[k] = 0;
    	}
    }
}

matters needing attention:

  1. The amount of data is too large, resulting in heap memory overflow
  2. Negative numbers cannot be sorted directly. If you want to deal with negative numbers, you need to improve.

6, Search algorithm (9.22)

  1. Sequential (linear) lookup
  2. Binary search
  3. Interpolation search
  4. fibonacci search

6.1 binary search

Binary search needs to find an ordered array

public static int binarySearch(int[] arr, int left, int right, int findVal){

    //Not found, end recursion
    if (left > right> return -1;

    int mid = (left + right) / 2;
    int midVal = arr[mid];
        
        
    if (findVal > midVal) {
        return binarySearch(arr, mid + 1, right, findVal);
    } else if (findVal < midVal) {
        return binarySearch(arr, left, mid - 1, findVal);
    } else {
        return mid;
        
        /*
        Add an index that returns all the same values
        List<Integer> resIndexList = new ArrayList<Integer>();
        int temp = mid - 1;
        while (true){
        	if (temp < 0 || arr[temp] != findVal) {break;}
        	
        	resIndexlist.add(temp);
        	temp -= 1;
        	//temp Shift left
        }
        resIndexlist.add(mid);
        
        //Scan right
        temp = mid + 1;
        while (true){
        	if (temp > arr.length - 1 || arr[temp] != findVal) {break;}
        	
        	resIndexlist.add(temp);
        	temp += 1;
        	//temp Shift right
        }
        
        return resIndexlist
        */
    }
}

6.2 interpolation search

//Write interpolation search algorithm (sequence order is required)
public static int insertValueSearch(int[] arr, int left, int right, int findVal) {
    if (left > right || findVal < arr[0] || findVal > arr[arr.length - 1]) return -1;
    
    int mid = left + (right - left) * (findVal - arr[left]) / (arr[right] - arr[left]);
    int midVal = arr[mid];
    if (findVal > midVal) {
        return insertValueSearch(arr, mid + 1, right, findVal);
    } else if (findVal < midVal) {
        return insertValueSearch(arr, left, mid - 1, findVal);
    } else {
        return mid;
    }
}
//Note: for the look-up table with large amount of data and uniform keyword distribution, interpolation search is faster
//Uneven (great jumping), not necessarily better than two points

6.3 Fibonacci (golden section) search algorithm

  1. Golden section point: a line segment is divided into two parts. The ratio of one part to the whole length is equal to that of the other part, with an approximate value of 0.618
  2. The ratio of two adjacent numbers in Fibonacci sequence is infinitely close to the golden section value of 0.618
//To create a Fibonacci sequence non recursively, you need to create a Fibonacci sequence first
public static int[] fib(){
    int[] f = new int[maxSize];
    f[0] = 1;
    f[1] = 1;
    for (int i = 2; i < maxSize; i++){
        f[i] = f[i - 1] + f[i - 2];
    }
    return f;
}

//If the length of Fibonacci is not enough by using non recursion, it needs to be supplemented
public static int fibSearch(int[] a, int key) {
    int low = 0;
    int high = a.length - 1;
    int k = 0;//Subscript representing the Fibonacci division value
    int mid = 0;
    int f[] = fib();
    //Get k
    while(high > f[k] - 1) {
        k++;
    }
    
    //Because the value of f[k] may be greater than the length of a, we need to construct a new array
    int[] temp = Arrays.copyOf(a, f[k]);
    for (int i = high + 1; i < temp.length; i++) {
        temp[i] = a[high];
    }
    
    //Use the while loop to find the key
    while (low <= high) {
        mid = low + f[k - 1] - 1;
        if (key < temp[mid]) {
            //Find left
            high = mid - 1;
            k--;
        } else if (key > temp[mid]) {
            //Find right
            low = mid + 1;
            //f[k] = f[k-1] + f[k-2];   So we continue the segmentation from the part of F [K-2]
            k -= 2;
        } else {
            //When you find it, make sure to put the subscript back
            if (mid <= high) {
                return mid;
            } else {
                return high;
            }
        }
    }
}

7, Hash table

java program > cache products (redis, memcache) / hash table (array + linked list, array + binary tree) > L2 cache > Database

Hash table: (hash table), a data structure accessed according to the key value. Records are accessed by mapping the key value to a position in the table to speed up the search. This mapping function is called hash function, and the array storing records is called Hash list.

Manage employee information with hash table:

public class HashTabDemo{
    
}

//Create hashTab to manage multiple linked lists
class HashTab{
    private EmpListedList[] empLinkedListArray;
    private int size;
    
    //
    public HashTab(int size) {
        this.size = size;
        empLinkedListArray = new EmpLinkedList[size];
        //
    }
    
    //Add employee
    public void add(Emp emp) {
        //According to the employee's id, get the linked list to which the employee should be added
        int empLinkedListNo = hashFun(emp.id);
        
        empLinkedListArray[empLinkedListNo].add(emp);
    }
    //Traverse all linked lists
    public void list(){
        for (int i = 0; i < size; i++) {
            empLinkedListArray[i].list();
        }
    }
    
    //Hash function, using simple modular method
    public int hashFun(int id) {
        return id % size;
    }
    
    //Find the employee based on the entered id
    public void findEmpById(int id){
        int empLinkedListNo = hashFun(id);
        Emp emp = empLinkedListArray[empLinkedListNo].findeEmpById(id);
        if (emp == null) {} else {}
    }
}


class Emp{
    public int id;
    public String name;
    public Emp next;
    public Emp(){
        
    }
}

class EmpLinkedList{
    //Header pointer, execute the first emp
    private Emp head;
    
    //Add employee to linked list
    
    public void add(Emp emp) {
        if (head == null) {
            head = emp;
            return;
        }
        //Not the first, use the auxiliary pointer to locate the last
        Emp curEmp = head;
        while(true) {
            if (curEmp.next == null) {
                break;
            }
            curEmp = curEmp.next;
        }
        
        curEmp.next = emp;
    }
    
    //Employee information traversing the linked list
    public void list(){
        if (head == null) {
            return;
        }
        Emp cuEmp = head;
        while (true){
            //syso id\name
            if(curEmp.next == null) break;
            curEmp = curEmp.next;
        }
    }
    
    
    //Find employees by id
    public Emp findEmpById(int id) {
        //Determine whether the linked list is empty
        if (head == null) {
            return null;
        }
        
        //Auxiliary pointer
        Emp curEmp = head;
        while (true) {
            if (curEmp.id == id) {
                break;
            }
            if (curEmp.next == null){
                curEmp = null;
                break;
            }
            curEmp = curEmp.next;
        }
        
        return curEmp;    
    }
}

8, Tree

8.1 Foundation (r1 9.26)

8.2 binary tree

  1. A tree with up to two child nodes per node
  2. Child nodes are divided into left nodes and right nodes
  3. If all leaf nodes of the binary tree are in the last layer, and the total number of nodes = 2^n-1,n is the number of layers, which is called full binary tree
  4. If all leaf nodes of the binary tree are in the last or penultimate layer, and the leaf nodes of the last layer are continuous on the left and the leaf nodes of the penultimate layer are continuous on the right, it is called a complete binary tree.
  5. According to the output of the parent node, traversal is divided into the first, middle and last three types. Pre order traversal: first output the parent node, left subtree, right subtree, and so on.
public class BinaryTreeDemo {
    main{
       
    }
}
//Define BinaryTree binary tree
class BinaryTree {
    private HeroNode root;
    
    public void setRoot(HeroNode root){
        this.root = root;
    }
    
    public void preOrder() {
        if (this.root != null) {
            this.root.preOrder();
        } else //syso null
        {}
        
    }
    
    public void infixOrder() {
        
    }
    //Postorder traversal
    public void postOrder(){
        
    }
}

class HeroNode {
    private int no;
    private String name;
    private HeroNode left;
    private HeroNode right;
    public HeroNode(int no, String name) {
        super();
        this.no = no;
        this.name = name;
    }
    
    //get set
    //toString
    
    //Write preorder traversal
    public void preOrder() {
        //syso this
        if (this.left != null) {
            this.left.preOrder();
        }
        if (this.right != null) {
            this.right.preOrder();
        }
    }
    
    
    //Middle order traversal
    public void infixOrder(){
        if (this.left != null){
            this.left.infixOrder();
        }
        
        //syso this
        
        if (this.right != null){
            this.right.infixOrder();
        }
    }
    
    
    //Postorder traversal
    public void postOrder(){
        if (this.left != null){
            this.left.postOrder();
        }
        if (this.right != null) {
            this.right.postOrder();
        }
        
        //syso this
    }
}
8.2.1 binary tree - find the specified node
//Preorder traversal
public HeroNode preOrderSearch(int no) {
    if (root != null) return root.postOrderSearch(no);
    else return null;
}

//Preorder traversal search
public HeroNode preOrdersearch(int no) {
    //Compare whether the current node is
    if (this.no == no) {
        return this;
    }
    //Then judge whether the left child node of the current node is empty. If not, recursive preorder search
    HeroNode resNode = null;
    
    if (this.left != null) {
        resNode = this.left.preOrderesearch(no);
    }
    
    if (resNode != null) return resNode;
    
    //1. Left recursive preorder search
    //2. Right
    if (this.right != null) resNode = this.right.preOrdersearch(no);
    
    return resNode;
}
8.2.2 deleting nodes
//Simple requirements: 1 Directly delete leaf nodes, 2 Delete subtree for non leaf node
//Idea: 1 Because the binary tree is one-way, we judge whether the child nodes of the current node need to be deleted, rather than whether the node needs to be deleted
//Because the parent node cannot be found directly
//2 consider whether it is an empty tree root or just one root node

//binaryTree
public void delNode(int no) {
    if (root != null) {
        if (root.getNo() == no) {
            root = null;
        }else {
            root.delNode(no);
        }
    } else {
        //syso null
    }
}


//Recursively delete nodes
public void delNode(int no) {
    if (this.left != null && this.left.no == no) {
        this.left = null;
        return;
    }
    
    
    if (this.right != null && this.right.no == no){
        this.right = null;
        return;
    }
    
    
    if (this.left != null) {
        this.left.delNode(no);
    }
    
    if (this.right != null) {
        this.right.delNode(no);
    }
}

Binary tree storage order

Basic description: from the perspective of data storage, the storage mode of array and tree can be converted to each other.

characteristic:

  1. Sequential binary trees usually only consider complete binary trees
  2. The left child node of the nth element is 2 * n + 1; The right child node is 2 * n + 2; Parent node is (n - 1) / 2
class ArrBinaryTree{
    private int[] arr;// An array that stores data nodes
    
    public ArrBinaryTree(int[] arr) {
        this.arr = arr;
    }
    
    public void preOrder(){
        this.preOrder(0);
    }
    
    //Write a method to complete the preorder traversal of the sequential storage binary tree
    public void preOrder(int index) {
        //If the array is empty, or arr.length = 0
        if (arr == null || arr.length == 0) 
            //syso is null
        if (index * 2 + 1 < arr.length) {
            preOrder(2 * index + 1);
        }
        //Right recursive traversal
        if ((index * 2 + 2) < arr.length) {
            
        }
    }
}

8.4 cued binary tree (9.23)

Basic introduction:

  1. The binary list of N nodes contains n + 1 (2n - (n - 1) = n + 1) empty finger fields. The null pointer field in the binary linked list is used to store the pointer to the predecessor and successor nodes of the node in a certain traversal order (this additional pointer is called clue)
  2. Clue linked list, clue binary tree, pre order clue binary tree, middle order clue binary tree, post order
  3. Precursor node: the previous node of a node
//Medium order cued subtree
public void threadedNodes(HeroNode node) {
    //If node == null, it cannot be threaded
    if (node == null) return;
    
    //1. Cued left subtree
    threadedNodes(node.getLeft());
    
    //2. Cue the current node
    //Process the precursor node of the current node
    if (node.getLeft() == null) {
        //Make the left pointer of the current node point to the predecessor node
        node.setLeft(pre);
        //The pointer to the current node type is modified to the left
        node.setLeftType(1);
    }
    
    //Process the successor nodes of the current node
    //When the node moves to the next node, the point (pre) of the previous node of the node connects the successor to the node
    if (pre != null && pre.getRight() == null) {
        pre.setRight(node);
        pre.setRightType(1);
    }
    
    //*****After each node is processed, let the current node be the precursor node of the next node
    pre = node;
    
    //3. Cued right subtree
    threadedNodes(node.getRight());
}
8.4.1 traversing cued binary tree

Traverse the binary tree with medium order cueing

Analysis: after cueing, the direction of each node changes, so the original traversal method cannot be used. Each node can be traversed by linear method without recursion, which also improves the efficiency of traversal. The order of traversal should be consistent with that of middle order traversal.

//Method of traversing cued binary tree
public void threadedList() {
    HeroNode node = root;
    while (node != null) {
        while (node.getLeftType() == 0){
            node = node.getLeft();
        }
        
        //syso this node
        while (root.getRightType == 1) {
            //Gets the successor node of the current node
            node = node.getRight();
            //syso node
        }
        
        //Replace traversed nodes
        node = node.getRight();
    }
}


8.5 heap sorting (r1)

  1. Select sort, unstable sort, complexity O(nlogn)

  1. Generally, large top pile is used in ascending order and small top pile is used in descending order
  2. By using the operation of large top heap and small top heap for the array

//i: Index of non leaf node in array
//length: decrease gradually, indicating how many elements are adjusted
//Adjust an array (binary tree) to a large top heap
public static void adjustHeap(int arr[], int i, int length){
    int temp = arr[i];
    //Start adjustment
    for (int k = i * 2 + 1; k < length; k = k * 2 + 1) {
        //i * 2 + 1 is the left child node of node i; k = k * 2 + 1 indicates the next left child node of the current node
        if (k+1< length && arr[k] < arr[k + 1]) {
            k++; //K points to the right child node
            
        }
        
        if (arr[k] > temp) {
            arr[i] = arr[k];
            i = k; 
        } else {
            break;
        }
    }
    
    //At the end of the loop, we have placed the maximum value of the tree with i as the parent node at the top (local)
    arr[i] = temp;
}


public static void heapSort(int arr[]){
    //1. Build an unordered sequence into a heap, and select the large top heap / small top heap according to the ascending and descending requirements
    //Arr.length/2 - 1 find the largest non leaf node
    for (int i = arr.length / 2 - 1; i >= 0; i--){
        adjustHeap(arr, i, arr.length);
    } //This is the large top pile
    
    //2. Exchange the top heap element with the end element, and "sink" the largest element to the end of the array
    //3. Readjust the structure to meet the heap definition, then continue to exchange the top elements of the heap with the current tail elements, and repeat the adjustment + exchange steps until the whole sequence is in order
    for (int j = arr.length - 1; j > 0; j--) {
        //exchange
        temp = arr[j];
        arr[j] = arr[0];
        arr[0] = temp;
        adjustHeap(arr, 0, j);
    }
}

9, Huffman tree

Basic introduction:

  1. Given n weights as n leaf nodes, a binary tree is constructed. If the weighted path length of the tree reaches the minimum, it is called the optimal binary tree, also known as Huffman tree.
  2. Huffman tree is the tree with the shortest weighted path length, the node with larger weight is closer to the root, and the tree with the smallest wpl
  3. The weight points are located in the leaf node
  4. Take two smallest root nodes to form a binary tree. The weight of the root node of the binary tree is the sum of the two nodes

matters needing attention:

  1. The file itself is compressed, and the recompression efficiency will not change significantly by using Huffman coding, such as ppt, video and other files
  2. Huffman can process all text by binary encoding
  3. If there is not much duplicate data in a file, the compression effect will not be obvious

//Create node class
//In order to keep the Node objects sorted, the Collections collection is sorted
class Node implements Comparable<Node>{
    int value; //Node weight
    Node left;
    Node right;
    
    public Node (int value){
        this.value = value;
    }
    
    //toString
    
    @override
    public int compareTo(Node node) {
        //Sort from small to large
        return this.value - o.value;
    }
}

public class HuffmanTree{
    //Create Huffman tree
    public static NodeX createHuffmanTree(int[] arr) {
        //1. Traversal 2 Build each element of arr into Node3 Put Node into ArrayList
        List<Node> nodes = new ArrayList<Node>();
        for (int value : arr) {
            nodes.add(new Node(value));
        }
        
        while (nodes.size() > 1) {
            
        
        
        Collections.sort(nodes);
        
        //Take out the node with the smallest weight (binary tree)
        Node left = nodes.get(0);
        //Take out the second smallest node
        Node right = nodes.get(1);
        
        //
        Node parent = new Node(left.value + right.value):
        parent.left = left;
        parent.right = right;
        
        //Delete the processed binary tree from the list
        nodes.remove(left);
        nodes.remove(right);
        nodes.add(parent);
                    
            
            }
        
        return nodes.get(0);
    }
}

9.1 Huffman code

  1. A coding algorithm

  2. Huffman coding is widely used in data file compression. The compression rate is usually between 20% - 90%, lossless compression

  3. Huffman code is a kind of vlc with variable length coding.

  4. Fixed length encoding: convert all bytes into binary

  5. Variable length coding: first count the occurrence times of characters and code according to the occurrence times of each character. The more the occurrence times, the smaller the coding.

  6. Prefix code: the code of characters cannot be the prefix of other character codes. The code that meets this requirement is called prefix code. That is, duplicate codes cannot be matched.

  7. instable

9.2 data compression

public static void main(String[] args){
    String content = "";
    byte[] contentBytes = content.getBytes();
    
    
}

//Receive byte array and put it back in list
private static List<Node> getNodes(byte[] bytes){
    
    //1. Create an ArrayList
    ArrayList<Node> nodes = new ArrayList<Node>();
    
    //Traverse bytes, count the number of occurrences of each byte, and store it in map
    Map<Byte, Integer> counts = new HashMap<>();
    for (byte b: bytes){
        Integer count = counts.get(b);
        if (count == null) {
            //New characters encountered for the first time
            counts.put(b, 1);
        } else {
            counts.put(b, count + 1);
        }
    }
    
    //Convert each key value into a Node object and add it to the nodes collection
    //Traversal map
    for (Map.Entry<Byte, Integer> entry : counts.entrySet()) {
        nodes.add(new Node(entry.getKey(), entry.getValue()));
    }
    
    
    return nodes;
}

//
private static Node createHuffmanTree(List<Node> nodes) {
    
    while (nodes.size() > 1) {
        //Sort, small to large
        Collections.sort(nodes);
        //Take out the first smallest binary tree
        Node leftNode = nodes.get(0);
        
        Node rightNode = nodes.get(1);
        
        //Create a new binary tree. Its root node has no data but only weights
        Node parent = new Node(null, leftNode.weight + rightNode.weight);
        parent.left = leftNode;
        parent.right = rightNode;
        
        //Delete the two binary trees that have been processed from nodes
        nodes.remove(leftNode);
        nodes.remove(rightNode);
        //Add a new binary tree to nodes
        nodes.add(parent);
    }
    
    //The last node of nodes is the root node
    return nodes.get(0);
}

//Create Node, data and weight
class Node implements Comparable<Node>{
    Byte data; //Store the data (character) itself, such as' a '- 97
    int weight; //Weight (number of characters)
    Node left;
    Node right;
    public Node(Byte data, int weight) {
        super();
        this.data = data;
        this.weight = weight;
    }
    
    @Override
    public int compareTo(Node o) {
        //Sort from small to large
        return this.weight - o.weight;
    }
    
    //toString
    
    //Preorder traversal
    public void preOrder(){
        //syso this
        if (this.left != null) this.left.preOrder();
        
        if (this.right != null) this.right.preOrder();
    }
}

9.3 generate Huffman code (9.27)

Generating Huffman coding and obtaining Huffman coded data

0 to the left and 1 to the right

//thinking
//1. Store Huffman coding table in map, where map < byte, string >
//	Form: 32 > 01, 97 > 100, u > 11001
// 2. While generating Huffman coding table, continuously splice character paths and define a path where StringBuilder stores a leaf node
static StringBuilder stringBuilder = new StringBuilder();
static Map<Byte, String> huffmanCodes = new HashMap<Byte, String>();

main{
    List<Node> nodes = getNodes(contentBytes);
    Node huffmanTreeRoot = createHuffmanTree(nodes);
    getCodes(huffmanTreeRoot, "", sb);// Root node is empty
}

//The Huffman codes of all leaf nodes of the incoming node node are obtained and put into the Huffman codes collection
//code the left child node is 0 and the right child node is 1
private static void getCodes(Node node, String code, StringBuilder sb){
    StringBuilder sb2 = new StringBuilder(sb);
    sb2.append(code);
    if (node != null) {
        //Judge whether the current node is a leaf node or a non leaf node
        if (node.data == null) {
            //Recursive processing of non leaf nodes
            getCodes(node.left, "0", sb2);
            getCodes(node.right, "1", sb2);
            
        } else {
            //Indicates that the last node of a leaf is found
            huffmanCodes.put(node.data, sb2.toString());
        }
    }
}


//The byte [] array corresponding to the string, through the generated Huffman encoding table, returns a byte [] compressed by Huffman encoding
//Get the character array corresponding to Huffman coding table
//Input string and output encoded data
private static byte[] zip(byte[] bytes, Map<Byte, String> hfCode) {
    StringBuilder sb = new StringBuilder();
    
    for (byte b : bytes) {
        sb.append(hfCode.get(b));
    }
    
    // syso sb.toString();
    // Add "101010101010....." Convert to byte []
    int len; // (sb.length() + 7) / 8;
    if (stringBuilder.length() % 8 == 0) {
        len = sb.length() / 8;
    } else {
        len = sb.length() / 8 + 1;
    }
    
    //Create byte array to store compressed data
    byte[] by = new byte[len];
    int index = 0;
    
    for (int i = 0; i < sb.length(); i+= 8) {
        //Every 8 bits corresponds to a byte
        String strByte;
        if (i+8 > sb.length()) {
            //The last time is less than 8
            strByte = sb.substring(i);
        } else {
            strByte = sb.substring(i, i + 8);
        }
        
        
        //Convert strbyte into a byte and put it in by
        by[inde] = (byte)Integer.parserInt(strByte, 2);
        index++;
    }
}

9.4 data decompression

1. Convert the original Huffman coded character array into binary string

//1.   [-88,-65,-56....] > "10101000..."
//2. "1010100..." > "i like like..."

//Complete the decoding of compressed data
// 1 Huffman encoding table 2 character array obtained by Huffman decoding
private static byte[] decode(Map<Byte, String> hfcodes, byte[] hfbytes) {
    //1. Get binary string first
    StringBuilder sb = new StringBuilder();
    //
    for (int i = 0; i < hfcodes.length; i++){
        byte b = hfbytes[i];
        boolean flag = (i == hfbytes.length - 1);
        sb.append(byteToBitString(!flag, b));
    }
    
    //2. Decode the string according to the specified Huffman encoding table
    // a> 100 > a exchange
    Map<String, Byte> map = new HashMap<String, Byte>();
    for (Map.Entry<Byte, String> entry : hfcodes.entrySet()) {
        map.put(entry.getValue(), entry.getKey());
    }
    //Create a byte to store for the collection
    List<Byte> list = new ArrayList<>();
    //
    for (int i = 0; i < sb.length; ){
        int count = 1; //Counter
        boolean flag = true;
        Byte b = null;
        
        while (flag) {
            //Take out a '1' or '0'
            String key = sb.substring(i, i+count);//i don't move, count moves until it matches a character
            b = map.get(key);
            if (b == null) {
                count++;
            } else {
                //Match to
                flag = false;
            }
        }
        list.add(b);
        i+=count; //i move directly to count
        
    }
    
    //
    byte b = new byte[list.size()];
    for (int i = 0; i < b.length; i++) {
        b[i] = list.get(i);
    }
    
    return b;
}

//flag: indicates whether to fill the high bit. The last byte does not need to fill the high bit
//return: returns the binary string corresponding to b by complement
private static String byteToBitString(boolean flag, byte b) {
    //1.   [-88,-65,-56....] > "10101000..."
    //Save b with variable
    int temp = b;// Convert b to int
    
    //If it is a positive number, there is a high complement
    if (flag){
        temp |= 256; // Bitwise and 256 1 0000 | 0000 00001 > 1 0000 0001
    }
    
    String str = Integer.toBinaryString(temp); //The binary complement corresponding to temp is returned
    
    if (flag) {
        return str.substring(str.length() - 8);
    } else {
        return str;
    }
    
    
    
    
    
    return 
}

10, Binary sort tree (BST) (9.28)

Improve retrieval, sorting, addition and deletion

Binary sort tree: (BST: binary sort (search) tree). For any non leaf node of the binary sort tree, the value of the left child node is required to be smaller than that of the current node, and the value of the right child node is required to be larger than that of the current node. The same value is placed on the left or right child node of the point.

10.1 binary sort tree creation and traversal

Create an array into the corresponding binary sort tree, and use the middle order to traverse the binary sort tree (the values traversed by the middle order are orderly)

//Create node
class Node {
    int value;
    Node left;
    Node right;
    
    //constructor
   //Add node
    public void add(Node node) {
        //Adding nodes in the form of recursion needs to meet the requirements of binary sort tree
        if (node == null) {
            return;
        }
        
        //Judge the value of the incoming node and its relationship with the value of the root node of the current subtree
        if (node.value < this.value) {
            if (this.left == null) {
                this.left = node.value;
            } else {
                this.left.add(node);
            }
            
        } else {
            if (this.right == null) {
                this.right = node.value;
            } else {
                this.right.add(node);
            }
        }
    }
    
    
    //Middle order traversal
    public void infixOrder() {
        if (this.left != null) {
            this.left.infixOrder();
        } 
        //syso this.value
        if (this.right != null) {
            this.right.infixOrder();
        }
    }
}

//Create binary sort tree
class BinarySortTree {
    private Node root;
    //Method of adding nodes
    public void add(Node node) {
        if (root == null) {
            root = node;
        } else {
            root.add(node);
        }
    }
    
    //Middle order traversal
    public void infixOrder() {
        if (root != null) {
            root.infixOrder();
        } else {
            // null
        }
    }
    
    //Find the node to delete
    public Node search(int value){
        if (root == null) return null;
        else {
            return root.search(value);
        }
    }
    
    //Find parent node
    public Node searchParent(int value){
        if (root == null) return null;
        else return root.searchParent(value);
    }
    
    public int delRightTreeMin(Node node) {
        //f returns the value of the smallest node of the binary sort tree with node as the root node
        //Delete the smallest node of the binary sort tree whose node is the root node
        Node target = node;
        while (target.left != null) {
            target = target.left;
        }
        //At this point, the target points to the smallest node
        delNode(target.value);//delete
        
        return target.value;
    }
    
    //Delete node
    public void delNode(int value) {
        if (root == null){
            return;
        } else {
            Node targetNode = search(value);
            if (targetNode == null) {
                return;
            }
            //If only one node is found
            if (root.left == null && root.right == null) {
                root == null;
                return;
            }
            
            //Find the parent node of tgnode
            Node parent = searchParent(value);
            //If the deleted node is a leaf node
            if (targetNode.left == null && targetNode.right == null) {
                
                
                //Determine whether tg is the left child node or the right child node of the parent node
                if (parent.left != null && parent.left.value == value) {
                    parent.left = null;
                } else if (parent.right != null && parent.right.value == value) {
                    parent.right = null;
                }
            } else if (targetNode.left != null && targetNode.right != null) {
                //Delete a node with two subtrees
                int minval = delRightTreeMin(targetNode.right);
                targetNode.value = minval;
                //Find the smallest from the right subtree
            } else {
                //Delete the node of a subtree
                //Note: when there are two remaining nodes, you need to judge the existence of the root node
                
                if (targetNode.left != null){
                    
                    if (parent != null) {
                        
                    
                    if (parent.left.value == value) {
                        parent.left = targetNode.left;
                    } else {
                        parent.right = targetNode.right;
                    } } else root = targetNode.left;
                } else {//The deleted node has a right child node
                    
                    if (parent != null) {
                    if (parent.left.value == value) {
                        parent.left = targetNode.left;
                    } else {
                        parent.right = targetNode.right;
                    } } else root = targetNode.right;
                }
            }
        }
    }
    
    
}


10.2 deletion of binary sort tree

Consideration:

  1. Delete the leaf node (1. Find the node to be deleted first. targetNode 2. Find the parent node of targetNode 3. Determine whether the left child node or the right child node. parent.left= null;/ parent.right = null)
  2. Delete a node with only one subtree(
    1. 123 \
    2. target is the left child node of parent: parent left = targetNode. left; \ parent. left = targetNode. right;)
  3. Delete a node with two subtrees(
    1. 12 \
    2. Find the smallest node from the right subtree of targetNode,
    3. Save the value of the smallest node in temp with a temporary variable,
    4. Delete the minimum node, t
    5. argetNode.value = temp;
    6. //Or find the largest node from the left subtree)
//Find the node to delete
public Node search(int value) {
    if (value == this.value) {
        return this;
    } else if (value < this.value) {
        //Left subtree recursive search
        if (this.left == null) {
            return null;
        }
        return this.left.search(value);
    } else {
        if (this.right == null) {
            return null;
        } 
        return this.right.search(value);
    }
} 

//Find the parent node of the node you want to delete
public Node searchParent(int value) {
    if ((this.left != null && this.left.value == value) || (this.right != null && this.right.value == value)) {
        return this;
    } else {
        if (value < this.value && this.left != null) {
            return this.left.searchParent(value);
        } else if (value >= this.value && this.right != null) {
            //Avoid the same value in actual use
            return this.right.searchParent(value);
        } else {
            //not found
            return null;
        }
    }
 }

//Other codes are in the previous section

11, Balanced binary tree (AVL)

Explain the possible problems of binary sort tree, which is also called balanced binary search tree

Case: {1, 2, 3, 4, 5, 6}, the binary tree formed is more like a single linked list, and the query is slower,

Problem analysis: all the left subtrees are empty, the insertion speed is not affected, the query speed is significantly reduced, and the advantages of bst cannot be brought into play. Solution: balance the binary tree.

Basic introduction:

  1. avl tree to ensure high query efficiency
  2. Features: the absolute value of the height difference between the left and right subtrees is no more than 1, and both the left and right subtrees are a balanced binary tree.
  3. Common implementation methods of balanced binary tree: red black tree, avl (algorithm), scapegoat tree, tree and extended tree

11.1 single rotation (left rotation)

Sequence 4 3 2 5 7 8,

Count the height of the left subtree and the height of the right subtree


class Node {
    int value;
    Node left;
    Node right;
    
    
    //constructor
   //****************************************************************
    //Returns the height of the tree with the current node as the root node
    public int height(){
        return Math.max(left == null ? 0 : left.height(), right == null ? 0 : right.height()) + 1;
    }
    
    public int leftHeight(){
        if (left == null) return 0;
        return left.height();
    }
    
    //Returns the height of the right subtree
    public int rightHeight(){
        if (right == null) return 0;
        return right.height();
    }
    
    //Left rotation method
    private void leftRotate() {
        //1. Create a new node to the value of the current root node
        Node new = new Node(value);
        
        new.left = left;
        new.right = right.left; 
        value = right.value;
        right = right.right;
        left = new;
    }
    
    //**********************************************************************
    //Add node
    public void add(Node node) {
        //Adding nodes in the form of recursion needs to meet the requirements of binary sort tree
        if (node == null) {
            return;
        }
        
        //Judge the value of the incoming node and its relationship with the value of the root node of the current subtree
        if (node.value < this.value) {
            if (this.left == null) {
                this.left = node.value;
            } else {
                this.left.add(node);
            }
            
        } else {
            if (this.right == null) {
                this.right = node.value;
            } else {
                this.right.add(node);
            }
        }
        
        //*************************************
        //After adding a node, if (height of right subtree - height of left subtree) > 1, rotate left
        if (rightHeight() - leftHeight() > 1) {
           // if (right != null && right.rightHeight() < right.leftHeight()) {
                //Rotate the right subtree first
            //}
            //Simple consideration, left rotation
            leftRotate();
        }
        
        // 
        if (leftHeight() - rightHeight() > 1) {
            rightRotate();
        }
    }
    
    
    //Middle order traversal
    public void infixOrder() {
        if (this.left != null) {
            this.left.infixOrder();
        } 
        //syso this.value
        if (this.right != null) {
            this.right.infixOrder();
        }
    }
}

11.2 right rotation

private void rightRotate(){
    Node new = new Node(value);
    new.right = right;
    new.left = left.right;
    value = left.value;
    left = left.left;
    right = new;
}

11.3 double rotation

Problem analysis:

  1. When the conditions for right rotation are met
  2. If the height of the right subtree of its left subtree is greater than the height of its left subtree
  3. First rotate the left node of the current node
  4. Then rotate the current node to the right
if(leftHeight() - rightHeight() > 1){
    if (left != null && left.rightHeight() > left.leftHeigth()) {
        left.leftRotate();
        rightRotate();
    } else {
        rightRotate();
    }
    return; // Must
}

if (rightHeight() - leftHeight() > 1) {
    //If the height of the left subtree of the right subtree is greater than the height of its right subtree
    //First rotate the right child node to the right, and then rotate the current node to the left
    if (right != null && right.leftHeight() > right.rightHeight()) {
        right.rightRotate();
        leftRotate();
    } else {
        leftRotate();
    }
    return;
}

12, Multiple lookup tree

12.1 binary tree and B-tree

The operation efficiency of binary tree is high, but there are also problems

Node of full binary tree: 2^n-1

The massive number of binary tree nodes causes problems: 1. During construction, i/o operations need to be carried out many times (massive data exists in the database or file). The massive number of nodes has an impact on the speed of constructing binary tree. 2.

2. The nodes are massive and the height of binary tree is very high, which reduces the operation speed.

Multitree:

Number of subtrees of nodes: degree of nodes

Maximum degree of all nodes: the degree of the tree

12.2-3 tree (9.29)

2-3 tree is a simple b-tree structure with the following features:

  1. All leaf nodes of the 2-3 tree are on the same layer (conditions satisfied by the b tree)
  2. 2-3 tree has only 2 and 3 nodes and 2 nodes (with two nodes or no nodes)
  3. Meet the characteristics of sorting array and abide by the rules of binary sorting tree
  4. When a number is inserted to a node according to the regulations, if the above three requirements cannot be met, it needs to be removed. First remove it upward, and if the upper layer is full, remove this layer.

12.3 B tree, B + tree, b * Tree

Balanced

B-tree

  1. Order of B tree: 23 tree = 3234 tree = 4, maximum number of child nodes of node
  2. Search performance: do a binary search in the complete set of keywords

B + tree

  1. Keywords are added to the linked list of leaf nodes (dense index)
  2. A non leaf node is equivalent to the index of a leaf node (sparse index)

B * Tree

13, Figure

Why are there pictures?

  1. The linear table is limited to the relationship between a direct precursor and a direct successor
  2. The tree can also have only one direct precursor (parent node)
  3. When we need to represent many to many relationships, we need to use graphs

Graph is a kind of data structure. Nodes can have zero or more adjacent elements, and there are edges between nodes.

  1. Undirected graph
  2. Directed graph
  3. Weighted graph (net)

Representation:

  1. Two dimensional array (adjacency matrix)
  2. Linked list (adjacency list)

13.1 implementation of undirected graph code

//Store vertex String using ArrayList 2 Save matrix int[][] edges
private ArrayList<String> vertexList;
private int[][] edges;//Storage graph corresponding adjacency matrix
private int numOfEdges;

public Graph(int n) {
    //Initialize matrix and vertexList
    edges = new int[n][n];
    vertexList = new ArrayList<String>(n);
    numOfEdges = 0;
}

public void insertVertex(String vertex) {
    //Insert node
    vertexList.add(vertex);
}

//Add edge
//v12 vertex subscript weight indicates weight
public void insertEdge(int v1, int v2, int weight) {
    edges[v1][v2] = weight;
    edges[v2][v1] = weight;
    numOfEdges++;
}

//Common methods return the number of nodes
public int getNumOfVertex(){
    return vertexList.size();
}
//Get the number of edges
public int getNumOfEdges(){
    return numOfEdges;
}
//Returns the data corresponding to the subscript of node i
public String getValue(int i) {
    return vertexList.get(i);
}

//Returns the weight of v1 v2
public int getWeight(int v1, int v2) {
    return edges[v1][v2];
}

//Corresponding matrix diagram

13.2 DFS

Basic steps:

  1. Access node, mark that the node has been accessed
  2. Find the first adjacent node
  3. Not accessed, the depth of the modified node takes precedence
//Defines the array boolean [], which records whether a node is accessed
private boolean[] isVisited = new boolean[5];//Initialization is written in the constructor

//Get the subscript of the first adjacent node
public int getFirstNeighbor(int index) {
    for (int j = 0; j < vertexList.size(); j++){
        if (edges[index][j] > 0) return j;
        
    }
    
    return -1;
}

//Obtain the next adjacent node according to the subscript of the previous adjacent node
public int getNextNeighbor(int v1, int v2) {
    for (int j = v2 + 1; j < vertexList.size(); j++) {
        if (edges[v1][j] > 0) return j;
        
        
    }
    return -1;
}

//DFS
public void dfs(boolean[] isVisited, int i) {
    //Access node
    //syso get(i)+">"
    //Tag access
    isVisited[i] = true;
    //Find the first adjacent node of node i
    int w = getFirstNeighbor(i);
    while (w != -1) {
        if (!isVisited[w]) {
            dfs(isVisited, w);
        }
        //If w has been accessed
        w = getNextNeighbor(i, w);
    }
    
    
}

main{
    graph.dfs();
}

//Reload dfs,
public void dfs() {
    //Traverse all nodes and perform dfs backtracking
    for (int i = 0; i < getNumOfVertex(); i++){
        if (!isVisited[i]) {
            dfs(isVisited, i);
        }
    }
}

13.3 BFS

Similar to the hierarchical search process, breadth first search needs to use a queue to maintain the order of visited nodes

//bfs for a node
private void bfs(boolean[] isVisited, int i) {
    int u; // Indicates the subscript corresponding to the header node of the queue
    int w; //Adjacent node w
    //Queue, record order
    LinkedList queue = new LinkedList();
    //Access node
    //syso
    //Tag access
    isVisited[i] = true;
    //Node join queue
    queue.addLast(i);
    
    while (!queue.isEmpty()) {
        //Take out the subscript of the queue header node
        u = (Integer)queue.removeFirst();
       
        //Get the subscript w of the first adjacent node
        w = getFirstNeighbor(u);
        while (w != -1) {
            if(!isVisited[w]) {
                //Output access
                //Tag access
                isVisited[w] = true;
                //Join queue
                queue.addLast(w);
            }
            
            w = getNextNeighbor(u, w);//Continue to find other adjacent node subscripts of the current layer
        }
    }
}

//Traverse all nodes for breadth first search
public void bfs() {
    isVisited = new boolean[verTexList.size()];
    for (int i = 0; i < getNumOfVertex(); i++) {
        if (!isVisited[i]) {
            bfs(isVisited, i);
        }
    }
}

13.4 summary

14, 10 commonly used algorithms

14.1 non recursive binary search

  1. The binary search algorithm is only suitable for searching from the ordered sequence (numbers, letters, etc.) and sorting the sequence
  2. The running time is log time O(logN), and it takes up to logN times to find the target
//Ascending sequence
public static int binarySearch(int[] arr, int target) {
    int left = 0;
    int right = arr.length - 1;
    while (left <= right) {
        int mid = (left + right) / 2;
        if (arr[mid] == target) return mid;
        else if (arr[mid] > target) {
            right = mid - 1;// You need to look to the left
            
        } else {
            left = mid + 1;
        }
    }
    
    return -1;
}

14.2 divide and conquer algorithm

divide and rule

  1. The complex problem is divided into several identical or similar subproblems, and then the solutions of subproblems that can be solved simply are combined. This technique is the basis of many efficient algorithms, such as sorting (fast sorting, merging) and Fourier transform (fast Fourier transform)
  2. Solving classical problems: binary search, large integer multiplication, chessboard coverage, merge sort, quick sort, linear time selection, closest point pair problem, round robin schedule, Hanoi tower
14.2.1 divide and conquer Hanoi Tower
  1. If there is only one disk, a - > C
  2. N > = 2, as two disks, the bottom disk and the top disk.
    1. First put the top plate a - > B
    2. Lowest a - > C
    3. b all b - > C
//
public static void hT(int num, char a, char b, char c) {
    if (num == 1) {
        //syso a - > c
    } else {
        //1. a-b
        hT(num - 1, a, c, b);
        //2. The bottom plate of a-C
        //syso a -> c
        //3. From B to c
        hT(num - 1, b, a, c);
    }
    
}

14.3 dynamic planning

Application scenario - Knapsack Problem

01 knapsack problem (one for each item at most), complete knapsack problem (without limiting the number of items, it can be changed to 01)

  1. Solving subproblems
  2. Different from divide and conquer, the subproblems obtained by decomposition are often not independent of each other. Based on the solution of the next sub stage, it is necessary to establish the solution of the next sub stage
  3. Dynamic programming can be advanced step by step by filling in the form to obtain the optimal solution

Thought - > formula (Law) - > code

//The i-th item w[i] item weight v[i] item value v[i][j] the maximum value c backpack capacity that can be loaded into the backpack with capacity j in the first I items traversed each time
/*
Fill in the form - find the law - get the formula
	1.v[i][0] = v[0][j] = 0 Indicates that the first row and column filled in the table are 0
	2.w[i] > j, v[i][j]=v[i-1][j]
	  //When the capacity of the new product to be added is greater than the capacity of the backpack, the loading strategy of the previous cell is directly used
	3.When J > = w [i], v [i] [J] = max {v [I-1] [J], v [I-1] [J-W [i]] + v [i]}
		//When the newly added commodity capacity to be added is less than or equal to the capacity of the current backpack, the loading method is as follows:
		//v[i-1][j]:Maximum loaded value of the previous cell
		//v[i]:Indicates the value of the current item
		//v[i-1][j-w[i]]:Maximum value of loading i-1 items into the remaining space j-w[i]
		Value of current goods + maximum value of goods in remaining space
*/

public static void main(String[] args) {
    int[] w = {1, 4, 3};
    int[] val = {1500, 3000, 2000};
    int m = 4;
    int n = val.length;
    
    //Create a 2D array
    int[][] v = new int[n+1][m+1];
    
    for (int i = 0; i < v.length; i++){
        v[i][0] = 0;
    }
    for (int i = 0; i < v[0].length; i++){
        v[0][i] = 0;
    }
    
    
    //According to the formula obtained above, dynamic programming is processed
    for (int i = 1; i < v.length; i++){
        //Do not process the first line
        for (int j = 1; j < v[0].length; j++){
            //
            if (w[i-1] > j){
                v[i][j] = v[i-1][j];
            } else {
                //i starts with 1 and needs - 1
                v[i][j] = Math.max(v[i-1][j], val[i - 1]+v[i-1][j-w[i-1]]);
                //Record the situation. You can't simply use the formula
                if ()
            }
        }
    }
    
    
}

14.4 KMP

Application scenario: string matching problem

Determine whether str1 contains str2

14.4.1 violence matching
  1. Character matching, for i++, j++

  2. Failed, str[i], make i=i-(j-1), j=0

  3. A lot of backtracking, moving only one bit at a time, wasting a lot of time, and there are repeated matches

    public static int violenceMatch(String str1, String str2) {
        char[] s1 = str1.toCharArray();
        char[] s2 = str2.toCharArray();
        
        int s1len = s1.length;
        int s2len = s2.length;
        
        int i = 0;
        int j = 0;
        while (i < s1len && j < s2len) {
            //Guarantee not to cross the line
            if (s1[i] == s2[j]) {
                i++;
                j++;
            } else {
                i = i - (j-1);
                j = 0;
            }
        }
        
        if (j == s2len) {
            return i - j;
        } else return -1;
    }
    
14.4.2 kmp

kmp is a classical algorithm to solve whether the pattern string has appeared in the text string, and if so, the earliest position

Using the previously judged information, save the length of the longest common subsequence in the pattern string through a next array. During each backtracking, find the previously matched position through the next array, saving a lot of calculation time.

How to omit the repeated steps?

Through some search words, the partial matching table of pattern string is calculated.



The essence of partial matching: there will be repetition at the head and tail of the string, and partial matching value is the length of repetition.

main{
    str1 = "sdsdsd  dsddsd";
    str2 = "sd";
}

//kmp search algorithm
public static int kmpSearch(String str1, String str2, int[] next) {
    
    for (int i = 0, j = 0; i < str1.length; i++){
        
        //Need to process STR1 charAt(i) !=  str2. charAt(j)
        // *******kmp core*********
        while (j > 0 && str1.charAt(i) != str2.charAt(j)) {
            j = next[j - 1];
        }
        
        
        if (str1.charAt(i) == str2.charAt(j)) {
        	j++;   
        }
        
        if (j == str2.length()) {//eureka
            return i - j + 1;
        }
    }
    
    return -1;
}


//Gets the partial matching value table of a string (substring)
public static int[] kmpNext(String dest) {
    //Create a next array to save some matching values
    int[] next = new int[dest.length()];
    next[0] = 0;
    for (int i = 1, j = 0; i++){
        //In case of inequality, we need to obtain a new j from next[j-1] until we find that there is equality and exit
        //***********kmp core***********
        while (j > 0 && dest.charAt(i) != dest.charAt(j)) {
            j = next[j - 1];
        }
        
        if (dest.charAt(i) == dest.charAt(j)) {
            j++;
        }
        next[i] = j;
    }
    return next;
}

14.5 greedy algorithm

Application scenario - set coverage problem

Introduction:

  1. When solving the problem, the best or optimal choice is taken in each step, so as to hope to lead to the best or optimal algorithm
  2. The results obtained are not necessarily the optimal results (sometimes the optimal solution), but they are relatively close to the optimal solution

Train of thought analysis:

  1. Exhaustive method, list all sets. It takes a lot of time.
  2. Greedy algorithm:

14.6 PLIM algorithm

Road construction problems:

14.6.1 minimum spanning tree (MST)

minimum cost spanning tree

Given a weighted undirected connected graph, if a spanning tree is selected to minimize the sum of weights on all edges of the tree, the characteristics are as follows:

  1. N vertices, n-1 edges
  2. Include all vertices
  3. n-1 edges are all in the graph
  4. Minimum spanning tree algorithm: prim algorithm, Kruskal algorithm
14.6.2 solution of PLIM algorithm
  1. Find the so-called minimal connected subgraph
  2. The algorithm is as follows:
    1. Let G=(v,e) be a connected graph, T=(u,d) be a minimum spanning tree, vu be a set of vertices, and ed be a set of edges
    2. If the minimum spanning tree is constructed from the vertex, take the vertex u from the set V and put it into the set, and mark the vertex v with visited[u]=1
    3. If there are edges between vertex ui in set u and vertex vj in set vu, find the edge with the smallest weight among these edges, but it cannot form a loop. Add vertex vj to set u, and add edges ui and vj to set d, indicating vj=1
    4. Repeat 2 until UVs are equal and mark visited
//prim

main{
    
}


//Create minimum spanning tree, figure
class MinTree{
    //Create adjacency matrix of graph
    public void createMragph(MGraph graph, int verxs, char data[], int[][] weight) {
        int i, j;
        for (i = 0; i < verxs; i++){
            graph.data[i] = data[i];
            for (j = 0; j < verxs; j++) {
                graph.weight[i][j] = weight[i][j];
            }
        }
    }
    
    
    //Show adjacency matrix of graph
    
    
    //Write prim algorithm to get the minimum spanning tree
    public void prim(MGraph graph, int v) {
        //v represents the vertex of the graph
        int visited[] = new int[graph.verxs]; // Mark whether the vertex has been accessed
        
        //Mark the current node as accessed
        visited[v] = 1;
        //h1 h2 records the subscripts of two vertices
        
        int h1 = -1;
        int h2 = -1;
        int minWeight = 10000;//Initialize a larger value and it will be replaced
        
        
        for (int k = 1; k < graph.verxs; k++) {
            
            
            for (int i = 0; i < graph.verxs; i++) {//Traverse visited nodes
                for (int j = 0; j < graph.verxs; j++) {//Traverse nodes that have not been accessed
                    
                
                if (visited[i] == 1 && visited[j] ==0 && graph.weight[i][j] < minWeight) {
                    //Replace minWeight
                    minWeight = graph.weight[i][j];
                    h1 = i;
                    h2 = j;
                }
            }}
            //Find an edge
            visited[h2] = 1;
            minWeight = 10000;
        }
    }
}


class MGraph{
    int verx; //Represents the number of nodes in the graph
    char[] data;//Store node data
    int[][] weight;//Storage edge, adjacency matrix
    
    public MGragh(int verxs){
        this.verxs = verxs;
        data = new char[verxs];
        weight = new int[verxs][verxs];
    }
}

14.7 kruskar

Bus station connectivity

Firstly, a forest with only n vertices is constructed, and then edges are selected from the connected network to join the forest according to the weight from small to large, so that there is no loop in the forest until the forest becomes a tree.

A weight sorting b adds the edge with the smallest weight in turn, and does not generate a loop. By judging whether there are the same final vertices

a - sorting algorithm

b - record the end point of the vertex in the "minimum spanning tree". The end point of the vertex is "the largest vertex connected with it in the minimum spanning tree". Then each time you need to add an edge to the minimum spanning tree, judge whether the end points of the two vertices of the edge coincide. If they coincide, a loop will be formed. The two vertices of the added edge cannot all point to the same end point.

//Get the end point () of the vertex with subscript i, which is used to judge whether the end points of the two vertices are the same
//The ends array records the corresponding end point of each vertex. The ends array is formed step by step in the process of traversal


private int getEnd(int[] ends, int i) {
    while (ends[i] != 0) {
        i = ends[i];
    }
    return i;
}

//Sort vertex classes


//kruskal
public void kruskal() {
    int index = 0; //Represents the index of the last result array
    int[] ends = new int[edgeNum]; //Used to save the end point of each vertex in the existing minimum spanning tree in the tree
    //Create a result array and save the last minimum spanning tree
    EData[] rets = new EData[edgeNum];
    
    //Get the set of all edges in the graph, 
    EData[] edges = getEdges();
    
    //Sort according to the weight of edges (from small to large)
    sortEdges(edges);
    
    //Traverse the edges array. When adding edges to the spanning tree, judge whether the added edges form a loop. If not, add rets, otherwise you can't join
    for (int i = 0; i < edgeNum; i++) {
        //Gets the first vertex (starting point) to the ith edge
        int p1 = getPosition(edges[i].start);
        //
        int p2 = getPosition(edges[i].end);
        
        int m = getEnd(ends, p1);
        //Get p2 the vertex at the end of the existing minimum spanning tree
        int n = getEnd(ends, p2);
        //Does it constitute a loop
        if (m != n) {
            ends[m] = n;//Set the end point of m in ends < e, f >
            
            rets[index++] = edges[i]; //Add an edge
        }
    }
}

14.8 dijestra

Shortest path problem

The main feature is to take the starting point as the center and expand to the outer layer (breadth first search idea) until it is extended to the end.

[the external link image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-umlx6h52-16447321619) (\ data structure and algorithm \ image.png)]

i] = data[i];
for (j = 0; j < verxs; j++) {
graph.weight[i][j] = weight[i][j];
}
}
}

//Show adjacency matrix of graph


//Write prim algorithm to get the minimum spanning tree
public void prim(MGraph graph, int v) {
    //v represents the vertex of the graph
    int visited[] = new int[graph.verxs]; // Mark whether the vertex has been accessed
    
    //Mark the current node as accessed
    visited[v] = 1;
    //h1 h2 records the subscripts of two vertices
    
    int h1 = -1;
    int h2 = -1;
    int minWeight = 10000;//Initialize a larger value and it will be replaced
    
    
    for (int k = 1; k < graph.verxs; k++) {
        
        
        for (int i = 0; i < graph.verxs; i++) {//Traverse visited nodes
            for (int j = 0; j < graph.verxs; j++) {//Traverse nodes that have not been accessed
                
            
            if (visited[i] == 1 && visited[j] ==0 && graph.weight[i][j] < minWeight) {
                //Replace minWeight
                minWeight = graph.weight[i][j];
                h1 = i;
                h2 = j;
            }
        }}
        //Find an edge
        visited[h2] = 1;
        minWeight = 10000;
    }
}

}

class MGraph{
int verx; // Represents the number of nodes in the graph
char[] data;// Store node data
int[][] weight;// Storage edge, adjacency matrix

public MGragh(int verxs){
    this.verxs = verxs;
    data = new char[verxs];
    weight = new int[verxs][verxs];
}

}

#### 14.7 kruskar

Bus station connectivity

First, construct a n Then select edges from the connected network to join the forest according to the weight from small to large, and make no loop in the forest until the forest becomes a tree.

a Weight sorting  b The edge with the smallest weight is added in turn, and no loop is generated, By judging whether there are the same final vertices



a - Sorting algorithm

b - Record the end point of the vertex in the "minimum spanning tree". The end point of the vertex is "the largest vertex connected with it in the minimum spanning tree". Then each time you need to add an edge to the minimum spanning tree, judge whether the end points of the two vertices of the edge coincide. If they coincide, a loop will be formed. The two vertices of the added edge cannot all point to the same end point.

```java
//Get the end point () of the vertex with subscript i, which is used to judge whether the end points of the two vertices are the same
//The ends array records the corresponding end point of each vertex. The ends array is formed step by step in the process of traversal


private int getEnd(int[] ends, int i) {
    while (ends[i] != 0) {
        i = ends[i];
    }
    return i;
}

//Sort vertex classes


//kruskal
public void kruskal() {
    int index = 0; //Represents the index of the last result array
    int[] ends = new int[edgeNum]; //Used to save the end point of each vertex in the existing minimum spanning tree in the tree
    //Create a result array and save the last minimum spanning tree
    EData[] rets = new EData[edgeNum];
    
    //Get the set of all edges in the graph, 
    EData[] edges = getEdges();
    
    //Sort according to the weight of edges (from small to large)
    sortEdges(edges);
    
    //Traverse the edges array. When adding edges to the spanning tree, judge whether the added edges form a loop. If not, add rets, otherwise you can't join
    for (int i = 0; i < edgeNum; i++) {
        //Gets the first vertex (starting point) to the ith edge
        int p1 = getPosition(edges[i].start);
        //
        int p2 = getPosition(edges[i].end);
        
        int m = getEnd(ends, p1);
        //Get p2 the vertex at the end of the existing minimum spanning tree
        int n = getEnd(ends, p2);
        //Does it constitute a loop
        if (m != n) {
            ends[m] = n;//Set the end point of m in ends < e, f >
            
            rets[index++] = edges[i]; //Add an edge
        }
    }
}

14.8 dijestra

Shortest path problem

The main feature is to take the starting point as the center and expand to the outer layer (breadth first search idea) until it is extended to the end.

Keywords: Algorithm data structure linked list

Added by postalservice14 on Sun, 13 Feb 2022 11:00:19 +0200