Discuss the philosophy of writing algorithm programs using "selection sort", the calculation of time and space complexity, and how to verify the correctness of the algorithm

Sorting algorithm - selection sort

Evaluation:
The simplest: the most consistent with people’s natural thinking
The least useful: basically not used in engineering practice

Time complexity: O(n^2)
Space complexity: O(1)

Contents of this section:
How to calculate time and space complexity
How to verify algorithms - random number generators, logarithms
The philosophy of writing algorithm programs

Selection sorting algorithm idea

An algorithm that is most in line with human thinking.
Each time it is traversed, find the smallest value and put it in front (swap) until all values ​​are found. The order is sorted. From small to large,
why is "exchange" instead of "insertion" here? My personal understanding: In memory arrangement, the "exchange" of array elements moves a smaller memory area, while "insertion" requires More memory areas are moved

How to write an algorithm program? The philosophy of writing algorithms

  • From simple to complex
    • Verify step by step
    • Print multiple intermediate results
  • Part first, then the whole
    • When you have no idea, break it down first.
  • First rough and then fine
    • Variable renaming
    • Statement merging
    • Boundary processing

Specific to the selection sort algorithm, how to write it?

From simple to complex: Ignore the double-layer loop first, write only the innermost loop, and only do the first core thing: the loop finds the subscript of the minimum value in the array. A closer split: there is a variable
specifically Record the subscript where the minimum value is located. First assume that the subscript is 0. Start selecting from the position of 1. When reaching a certain element, if the comparison finds that there is a smaller value than the value with the subscript 0, update the minimum value. The value of the value subscript variable is the new subscript

Rough version of code:

private static void sort1(int[] arr) {
    
    
    int minPos = 0;
    for (int i = 1; i < arr.length; i++) {
    
    
        if (arr[minPos] > arr[i]) {
    
    
            minPos = i;
        }
    }
    // 此时下标为 minPos 的值就是我们挑选出来的最小值
    System.out.println("minPos = " + minPos);
    System.out.println("arr = " + Arrays.toString(arr));
    // 交换: 将最小值与下标为0的值做交换
    int tmp = arr[0];
    arr[0] = arr[minPos];
    arr[minPos] = tmp;
    // 再次打印
    System.out.println("after arr1 = " + Arrays.toString(arr));

    // 第一轮执行完毕,准备第二轮
    minPos = 1;
    for (int i = 2; i < arr.length; i++) {
    
    
        if (arr[minPos] > arr[i]) {
    
    
            minPos = i;
        }
    }
    // 此时下标为 minPos 的值就是挑选出来的最小值
    System.out.println("minPos = " + minPos);
    System.out.println("arr = " + Arrays.toString(arr));
    // 交换: 将最小值与下标为1的值做交换
    tmp = arr[1];
    arr[1] = arr[minPos];
    arr[minPos] = tmp;
    // 交换后,下标为1的位置就是本轮挑选出来的最小值
    System.out.println("arr2 = " + Arrays.toString(arr));

    // ...
    // 发现规律:每一轮的结果就是挑选出一个最小值,并与指定下标的值交换
    // 待交换的下标是从0开始递增,直到length - 1
}

streamline

Discover the rules: The result of each round is to pick a minimum value and exchange it with the value of the specified subscript. The
subscript to be exchanged starts from 0 and increases until length - 1

private static void sort2(int[] arr) {
    
    
    for (int i = 0; i < arr.length - 1; i++) {
    
    
        int minPos = i;
        for (int j = i + 1; j < arr.length; j++) {
    
    
            if (arr[minPos] > arr[j]) {
    
    
                minPos = j;
            }
        }
        System.out.println("第 " + i + " 轮外层循环,找到的最小值下标: " + minPos);
        int tmp = arr[i];
        arr[i] = arr[minPos];
        arr[minPos] = tmp;
        System.out.println("交换后的数组 = " + Arrays.toString(arr));
    }
    System.out.println("arr = " + Arrays.toString(arr));
}

Compute time and space complexity

Analyze time complexity first, then analyze space complexity

Take the sort2 method as an example to calculate the time and space complexity, and analyze the time complexity of each sentence. For convenience of expression, a sentence of java code is expressed as a time complexity unit

Time complexity analysis

private static void sort2(int[] arr) {
    
     // 方法名,不计入复杂度,假设参数重的arr长度为n,以下的代码将以n为基础
    for (int i = 0; // 代码 i=0 只会执行一次,计为1
    		i < arr.length - 1; // 代码 i<arr.length-1 将执行 length-1 次,计为n-1,又因n很大的时候与n-1相差无几,所以可直接计为n
    		i++) {
    
     // 代码 i++ 将执行n次,计为n
        int minPos = i; // 执行 n-1 次,计为 n
        for (int j = i + 1; // 该语句将执行 (n-1) 次,与外层循环的次数一致
        	j < arr.length; // 该语句将执行 (n-1)+(n-2)+(n-3)+...+2+1 次,这是个等差数列,换算一下为: n(n-1)/2 = n^2/2 - n/2
        	j++) {
    
     // 该语句是上句话的次数+1,同理当n很大的时候,与n相关的+1相差无几,所以为了方便计算,+1就不在单独加一,即该语句与上句话的时间复杂度相同
            if (arr[minPos] > arr[j]) {
    
     // 该语句与等差数列的次数相同
                minPos = j; // 同上
            }
        }
        System.out.println("第 " + i + " 轮外层循环,找到的最小值下标: " + minPos); // 该语句是调试打印语句,不计入时间复杂度
        int tmp = arr[i]; 		// 该语句将执行 (n-1) 次
        arr[i] = arr[minPos]; 	// 同上
        arr[minPos] = tmp; 		// 同上
        System.out.println("交换后的数组 = " + Arrays.toString(arr)); 			// 调试打印语句,忽略
    }
    System.out.println("arr = " + Arrays.toString(arr)); 						// 调试打印语句,忽略
}

From the time complexity analysis of the above source code comments, the time complexity with the highest power is the arithmetic sequence, that is, the n^2/2 - n/2time complexity of the entire algorithm only needs to find the sentence with the highest power as the entire algorithm. The time complexity is enough.
Then simplify the complex formula, ignore the constant terms, ignore the low-power terms - only retain the highest power - the value is n^2, that is, the time complexity of the entire algorithm is:O(n^2)

It can be seen that the time complexity of two-level loops is n^2. In the future, you can directly search for multi-level loops. The basic time complexity of a basic-level loop is n raised to several powers.

Space complexity analysis

空间复杂度Refers to the additional space required by the algorithm.
Principle: Mainly look for the space related to the data size, and ignore individual basic type variables, such as the index variable in the for loop iand the index variable in the inner loop , and also ignore the variable selection and sorting algorithm jused for exchange , which is not additionally used. A space equivalent to the data volume, so space complexity is the most basicint tmp
O(1)

The “instability” of selection sorting

What is instability? That is, there are two elements with equivalent values ​​in an array. After selection sorting, the two elements may be exchanged. The relative position of these two elements is unstable

For example, assume that the following is an array to be sorted: add a debugging print code before the exchange occurs in
int[] arr = {5, 4, 2, 5, 1, 3};
the method :sort2()
System.out.printf("即将发生交换arr[%s]=%s <-> arr[%s]=%s\n", i, arr[i], minPos, arr[minPos]);

You can see the following output:

即将发生交换arr[0]=5 <-> arr[4]=1
即将发生交换arr[1]=4 <-> arr[2]=2
即将发生交换arr[2]=4 <-> arr[5]=3
即将发生交换arr[3]=5 <-> arr[5]=4
即将发生交换arr[4]=5 <-> arr[4]=5
arr = [1, 2, 3, 4, 5, 5]

We see that the last row of results shows that the sorting results are indeed arranged in order from small to large. This is the correct order, but don't worry, see if the element with the value 5 is swapped back and forth with the value subscripted to
0 The exchange path of 5: [0] -> [4]
The exchange path of the value 5 whose subscript is 3: [3] -> [5]
Some people say that the relative order of the two values ​​​​5 here has not changed, the first one 5 is swapped from position 0 to position 4, and the second 5 is swapped from position 3 to position 5. After the swap, they still maintain the relative order.
Don't worry, the above example was written by me casually, and it happened to not hit the special scene of instability. Next, we will use this example to slightly change the order of the original array to trigger the unstable scene. We will change the last two numbers
. 1 and 3 are exchanged to get the following array:
int[] arr = {5, 4, 2, 5, 3, 1};
We execute the selection sort algorithm again to get the output:

即将发生交换arr[0]=5 <-> arr[5]=1
即将发生交换arr[1]=4 <-> arr[2]=2
即将发生交换arr[2]=4 <-> arr[4]=3
即将发生交换arr[3]=5 <-> arr[4]=4
即将发生交换arr[4]=5 <-> arr[4]=5
arr = [1, 2, 3, 4, 5, 5]

The exchange path of the value 5 with the index 0: [0] -> [5] The
exchange path of the value 5 with the index 3: [3] -> [4]
At this time, the first 5 is exchanged from position 0 At position No. 5, the second 5 was swapped from position 3 to position 4, so the relative positions of the two 5s changed after their respective exchanges, and the instability scene was triggered.

Examples of the impact of unstable sorting on actual business

The bank's depositors are sorted from large to small in terms of deposit amount. However, there are a large number of depositors with equal amounts, so the order of depositors with equal amounts is unstable. Maybe a certain event just sends gifts to the top 1,000 largest depositors. Due to unstable sorting, the amount allocated to the Nth person is 500,000, and there are 100 depositors of exactly 500,000. If all 100 people are included in the gift range, the total number of people will reach 1,001, but Business rules strictly require that only the first 1,000 people can be included, so there must be a depositor with a deposit of 500,000 to be excluded.
The selection sorting algorithm cannot guarantee that the relative order of depositors with deposits of 500,000 before sorting remains unchanged. This is the "instability" of the selection sorting algorithm.

How to verify the algorithm?

Verification Algorithm – Logarithmizer (An instrument for comparing arrays)

  1. Visual observation – only used for test code, not engineering code, because: it is error-prone; it cannot be seen with the naked eye when the sample is large. So the steps start from item 2:
  2. Generate enough random samples
  3. Calculate sample results using the correct algorithm
  4. Compare the results of verified algorithms

Generate enough random samples

Generate an array, the number is specified by the parameter, then create a random object, and then generate a random integer for each subscript of the array. The maximum value of the random integer is specified by the parameter. The code is as follows:

private int[] generateRandomArray(int len, int max) {
    
    
    int[] arr = new int[len];
    Random r = new Random();
    for (int i = 0; i < arr.length; i++) {
    
    
        arr[i] = r.nextInt(max);
    }
    return arr;
}

Compare two arrays for equality

If the lengths are not equal, the arrays must be unequal. Otherwise, traverse the two arrays and take out the values ​​​​in the corresponding subscripts of the two arrays. For comparison, if unequal is found, unequal will be returned. If no unequal is found at the end of the traversal , then the return is equal, the code is as follows:

private boolean checkArrayEquals(int[] arr1, int[] arr2) {
    
    
    if (arr1.length != arr2.length) {
    
    
        return false;
    }

    for (int i = 0; i < arr1.length; i++) {
    
    
        if (arr1[i] != arr2[i]) {
    
    
            return false;
        }
    }
    return true;
}

Auxiliary printing of the first N elements of a large array

Since there are too many values ​​in a large array, it is inconvenient to print them all. In a sorting scenario, only checking whether the first N elements are in order can roughly reflect the order of the entire array. The code is as follows:

private void printFirstN(int[] arr, int n) {
    
    
    System.out.print("first-" + n + ": ");
    for (int i = 0; i < n; i++) {
    
    
        System.out.print(arr[i] + " ");
    }
    System.out.println();
}

Main functions of the verification algorithm

After completing the auxiliary function previously, you can write the main function. First randomly generate an array of 10,000 elements, and then copy one to get two copies. One is used for sorting by our own sorting algorithm, and the other is used for sorting by the standard sorting function. Then compare the results of the two sorting algorithms. ,code show as below:

public void test_data_checker() {
    
    
    for (int i = 0; i < 10; i++) {
    
    
        int[] arr = generateRandomArray(10000, 10000);
        int[] arr2 = new int[arr.length];
        System.arraycopy(arr, 0, arr2, 0, arr.length);
        printFirstN(arr, 10);
        SelectionSort.sort2(arr);
        Arrays.sort(arr2);
        printFirstN(arr, 10);
        printFirstN(arr2, 10);
        boolean b = checkArrayEquals(arr, arr2);
        if (!b) {
    
    
            throw new RuntimeException("排序结果与标准排序算法不一致");
        }
    }
}

Wrap the above logic in a loop and loop multiple times. If the result is different at one time, an exception message will be thrown.

Guess you like

Origin blog.csdn.net/booynal/article/details/125590320
Recommended