Java Basics Search and Sorting

1. Binary search(⭐)

Require

  • Be able to describe the binary search algorithm in your own language
  • Ability to hand-write binary search code
  • Able to answer some changed test methods

Binary search code algorithm idea

  1. Premise: There is a sorted array A (assuming it has been done)

  2. Define the left boundary L and the right boundary R, ​​determine the search range, and perform binary search in a loop (steps 3 and 4)

  3. Get intermediate index M = (L+R) /2

  4. The value A[M] of the intermediate index is compared with the value T to be searched

    ① A[M] == T means found, return the middle index

    ② A[M] > T, other elements on the right side of the middle value are greater than T, no need to compare, find the middle index on the left, set M - 1 as the right boundary, and search again

    ③ A[M] < T, other elements on the left side of the middle value are smaller than T, no need to compare, find the right side of the middle index, set M + 1 as the left boundary, and search again

  5. When L > R, it means not found, and the loop should end

Code

The following algorithm is implemented based on Arrays.binarySearch.

public class BinarySearch {
    
    
    public static void main(String[] args) {
    
    
        int[] a = {
    
    9, 3, 7, 2, 5, 8, 1, 4};
        Arrays.sort(a);
        int index = binarySearch(a, 7);
        System.out.println(index);
    }

    private static int binarySearch(int[] a, int target) {
    
    
        int l = 0, r = a.length - 1, mid;
        while (l <= r) {
    
    
            // 等价于(l+r)/2,但是如果r是Integer.MAX_VALUE的话,可能会导致溢出。
            mid = (l + r) >>> 1; 
            // a[mid]与target相同
            if (a[mid] == target) {
    
    
                return mid;
            }
            // a[mid]比target大,说明在左边
            if (a[mid] > target) {
    
    
                r = mid - 1;
            }
            // a[mid]比target小,说明在右边
            if (a[mid] < target) {
    
    
                l = mid + 1;
            }
        }
        return -1;
    }
}

multiple choice test

Motto: Odd-numbered two points take the middle, even-numbered two points take the middle to the left

  1. There is an ordered list of 1, 5, 8, 11, 19, 22, 31, 35, 40, 45, 48, 49, 50 When the node with a binary search value of 48 is found, the number of comparisons required for successful search

  2. When using the dichotomy method to find element 81 in the sequence 1,4,6,7,15,33,39,50,64,78,75,81,89,96, it needs to go through () comparisons

  3. To binary search a number in an array with 128 elements, the maximum number of comparisons required is no more than how many times

For the first two questions, remember a brief formula for judging: the odd two points take the middle, and the even two points take the middle to the left . For the latter question, you need to know the formula: n = log2^N So, 128 elements need 7 times, where n is the number of searches, and N is the number of elements

2. Bubble sort(⭐)

Require

  • Be able to describe the bubble sort algorithm in your own language
  • Ability to write bubble sort code by hand
  • Understand some optimization methods of bubble sorting

Bubble Sort Algorithm Ideas

  1. Compare the sizes of two adjacent elements in the array in turn. If a[j] > a[j+1], then exchange the two elements. Comparing both of them is called a round of bubbling. The result is to arrange the largest element to at last
  2. Repeat the above steps until the entire array is sorted

Code

public class BubbleSort {
    
    
    public static void main(String[] args) {
    
    
        int[] a = {
    
    9, 3, 7, 2, 5, 8, 1, 4};
        bubbleSort(a);
    }

    private static void bubbleSort(int[] a) {
    
    
        // 循环次数只用循环a.length-1次,比如说8个元素,只用循环7次即可排序完成。
        for (int j = 0; j < a.length - 1; j++) {
    
    
            // 记录是否进行交换,如果没不再交换了就直接退出循环。
            boolean flag = false;
            // 只用比较a.length-1-j次,因为有j个数已经排好了,没必要进行比较了。
            for (int i = 0; i < a.length - 1 - j; i++) {
    
    
                if (a[i] > a[i + 1]) {
    
    
                    swap(a, i, i + 1);
                    flag = true;
                }
            }
            // 如果这一遍循环没有进行交换,则说明数组已经排序好了,则直接退出循环。
            if (!flag) {
    
    
                break;
            }
            System.out.println(Arrays.toString(a));
        }
    }

    private static void swap(int[] a, int i, int j) {
    
    
        int temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }
}
  • Optimization point 1: After each round of bubbling, the inner loop can be reduced once ( realized by the inner loop condition -j )
  • Optimization point 2: If there is no exchange in a certain round of bubbling, it means that all data is in order, and the outer loop can be ended ( set the tag variable to achieve )

advanced optimization

public static void bubble_v2(int[] a) {
    
    
    int n = a.length - 1;
    while (true) {
    
    
        int last = 0; // 表示最后一次交换索引位置
        for (int i = 0; i < n; i++) {
    
    
            System.out.println("比较次数" + i);
            if (a[i] > a[i + 1]) {
    
    
                Utils.swap(a, i, i + 1);
                last = i;
            }
        }
        n = last;
        System.out.println("第轮冒泡"
                           + Arrays.toString(a));
        if (n == 0) {
    
    
            break;
        }
    }
}
  • During each round of bubbling, the last exchange index can be used as the number of comparisons for the next round of bubbling. If this value is zero, it means that the entire array is in order, and you can just exit the outer loop

3. Selection sort (unstable)

Require

  • Be able to describe the selection sort algorithm in your own language
  • Ability to compare selection sort with bubble sort
  • Understanding Unstable Sorting and Stable Sorting

Selection Sort Algorithm Ideas

  1. Divide the array into two subsets, sorted and unsorted, each round selects the smallest element from the unsorted subset and puts it into the sorted subset

  2. Repeat the above steps until the entire array is sorted

Code

public class SelectionSort {
    
    
    public static void main(String[] args) {
    
    
        int[] a = {
    
    9, 3, 7, 2, 5, 8, 1, 4};
        selectionSort(a);
    }

    private static void selectionSort(int[] a) {
    
    
        // 只用循环a.length-1次,比如说8个元素,只用循环7次即可排序完成。
        // i变量代表着每轮选择的最小元素要放到的索引位置。
        for (int i = 0; i < a.length - 1; i++) {
    
    
            // 每轮循环找到的最小元素,初始值从i开始
            int num = i;
            // 从当前元素开始,与后面所有元素进行比较,选出最小的元素。
            for (int j = num + 1; j < a.length; j++) {
    
    
                // 如果遍历到某个元素比a[num]小,则将该元素下标赋值给num
                if (a[num] > a[j]) {
    
    
                    num = j;
                }
            }
            if (num != i) {
    
    
                // 将这次循环找到的最小的元素放入i位置。
                swap(a, num, i);
            }
            System.out.println(Arrays.toString(a));
        }
    }

    private static void swap(int[] a, int i, int j) {
    
    
        int temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }
}
  • Optimization point: In order to reduce the number of exchanges, you can first find the smallest index in each round , and then exchange elements at the end of each round

Bubble Sort vs Selection Sort

  1. The average time complexity of both is O(n^2)
  2. Selection sorting is generally faster than bubbling because it has fewer exchanges (record subscript form) Insert>Select>Bubble
  3. But if the collection is highly ordered, bubbling is better than selection

4. Insertion sort

Require

  • Be able to describe the insertion sort algorithm in your own language
  • Ability to compare insertion sort with selection sort

Insertion sort algorithm ideas

  1. Divide the array into two areas, the sorted area and the unsorted area, each round takes the first element from the unsorted area and inserts it into the sorted area (the order needs to be guaranteed)

  2. Repeat the above steps until the entire array is sorted

Code

public class InsertSort {
    
    
    public static void main(String[] args) {
    
    
        int[] a = {
    
    9, 3, 7, 2, 5, 8, 1, 4};
        insertSort(a);
    }

    private static void insertSort(int[] a) {
    
    
        // i代表待插入元素的索引,从第二个元素开始,也就是下标为1的元素开始遍历。
        for (int i = 1; i < a.length; i++) {
    
    
            // 代表待插入的元素值
            int target = a[i];
            // sortedIndex代表已经排好序的元素末尾索引,初始值为i-1
            int sortedIndex = i - 1;
            for (; sortedIndex >= 0; sortedIndex--) {
    
    
                // 将新元素与前面的元素一个个比较,如果小于前面的元素
                if (target < a[sortedIndex]) {
    
    
                    // 前面的元素就往后移一位。
                    a[sortedIndex + 1] = a[sortedIndex];
                } else {
    
    
                    // 退出循环,减少比较次数。
                    break;
                }
            }
            a[sortedIndex + 1] = target;
            System.out.println(Arrays.toString(a));
        }
    }
}

Insertion sort vs selection sort

  1. The average time complexity of both is O(n^2)
  2. Insertion is slightly better than select most of the time. Insert > Select > Bubble
  3. Insertion time complexity of sorted set is O(n)

Advantages : For small data volume sorting, insertion sorting will be preferred

5. Hill sort (unstable)

Require

  • Be able to describe the Hill sorting algorithm in your own language

Hill sorting algorithm idea

  1. First select a gap sequence , such as (n/2, n/4 ... 1) , n ​​is the length of the array

  2. In each round, the elements with equal gaps are regarded as a group, and the elements in the group are inserted and sorted for two purposes.

    ① The insertion and sorting speed of a small number of elements is very fast

    ②Let the elements with larger values ​​in the group move to the back faster

  3. When the gap gradually decreases until it is 1, the sorting can be completed

6. Quick sort (unstable⭐)

Require

  • Be able to describe the quicksort algorithm in your own language
  • Master one of the handwritten unilateral loop and bilateral loop codes
  • Be able to explain the characteristics of quick sort
  • Understand the performance comparison of Lomuto and Hall partitioning schemes

Quick sort algorithm ideas (total)

    1. Let the elements smaller than the reference point enter one partition, and the elements larger than the reference point enter another partition
    2. When partitioning is complete, the position of the pivot element is its final position
  1. Repeat the above process in the sub-partition until the number of sub-partition elements is less than or equal to 1, which reflects the idea of ​​​​divide and conquer
  2. As can be seen from the above description, a key lies in the partition algorithm, common ones include the Lomuto partition scheme, the bilateral loop partition scheme, and the Hall partition scheme

Unilateral cyclic fast sorting (lomuto partition scheme)

  1. Select the rightmost element as the datum element

  2. The j pointer is responsible for finding an element smaller than the reference point , and once found, it is exchanged with i

  3. The i pointer maintains the bounds of elements smaller than the reference point , and is also the target index for each swap

  4. Finally, the reference point is exchanged with i, and i is the partition position

public class QuickSort1 {
    
    
    public static void main(String[] args) {
    
    
        int[] a = {
    
    9, 3, 7, 2, 5, 8, 1, 4};
        quickSort(a, 0, a.length - 1);
        System.out.println(Arrays.toString(a));
    }

    private static void quickSort(int[] a, int low, int high) {
    
    
        // 如果区间内没有元素,则直接return
        if (low >= high) {
    
    
            return;
        }
        // p是基准的索引值
        int p = partition(a, low, high);
        // 左边分区的递归
        quickSort(a, low, p - 1);
        // 右边分区的递归
        quickSort(a, p + 1, high);
    }

    /**
     * @param low  数组的左边界
     * @param high 数组的右边界
     */
    private static int partition(int[] a, int low, int high) {
    
    
        // pivot是基准点元素,这里选择数组最右边的元素作为基准点
        int pivot = a[high];
        int i = low;
        for (int j = low; j < high; j++) {
    
    
            // 如果当前元素小于pivot,就让i与j互换
            if (a[j] < pivot) {
    
    
                swap(a, i, j);
                i++;
            }
        }
        // 交换i与pivot,让基准点左边全是小于pivot的,右边全是大于pivot的。
        swap(a, high, i);
        return i;
    }


    private static void swap(int[] a, int i, int j) {
    
    
        int temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }
}

Bilateral circular fast sorting (not exactly equivalent to hoare Hall partition scheme)

  1. Select the leftmost element as the datum element
  2. The j pointer is responsible for finding elements smaller than the reference point from right to left
  3. The i pointer is responsible for finding elements larger than the reference point from left to right . Once found, the two are exchanged until i, j intersect
  4. Finally, the reference point is exchanged with i (at this time, i and j are equal), and i is the partition position

main point

  1. The reference point is on the left, and j should be followed by i
  2. while( i < j && a[j] > pivot ) j–
  3. while ( i < j && a[i] <= pivot ) i++

Why does the inner loop need to judge i<j

If the array is [5, 1, 2, 3, 6, 7, 8], first j–, find 3 from the back to the front, then find i++, find 6, and then exchange, there will be problems at this time.

public class QuickSort2 {
    
    
    public static void main(String[] args) {
    
    
        int[] a = {
    
    9, 3, 7, 2, 5, 8, 1, 4};
        quickSort(a, 0, a.length - 1);
        System.out.println(Arrays.toString(a));
    }

    private static void quickSort(int[] a, int low, int high) {
    
    
        // 如果区间内没有元素,则直接return
        if (low >= high) {
    
    
            return;
        }
        // p是基准的索引值
        int p = partition(a, low, high);
        // 左边分区的递归
        quickSort(a, low, p - 1);
        // 右边分区的递归
        quickSort(a, p + 1, high);
    }

    private static int partition(int[] a, int low, int high) {
    
    
        // 以左边的为基准元素
        int pivot = a[low];
        int i = low;
        int j = high;
        while (i < j) {
    
    
            // j 从右边开始,找比pivot小的元素下标
            while (i < j && a[j] > pivot) {
    
    
                j--;
            }
            // i 从左边开始,找比pivot大的元素下标
            while (i < j && a[i] <= pivot) {
    
    
                i++;
            }
            swap(a, i, j);
        }
        // 将基准元素与j/i进行交换,此时i与j指向的是同一元素。
        swap(a, low, j);
        System.out.println(Arrays.toString(a));
        return j;
    }

    private static void swap(int[] a, int i, int j) {
    
    
        int temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }
}

Quick sort features

  1. Average time complexity is O(nlog2^⁡n ), worst time complexity O(n^2)

  2. When the amount of data is large , the advantage is very obvious

Lomuto Zoning Scheme vs Hall Zoning Scheme

  • Hall moves 3 times less than Lomuto on average

Stable sort and unstable sort

Stable sorting refers to multiple sorting by different fields in the object (such as sorting by suit first and then sorting by size), without disturbing the order of elements with the same value , and vice versa for unstable sorting.
insert image description here

Guess you like

Origin blog.csdn.net/weixin_45930241/article/details/123696341