Chapter 2: demo code implementation (Java version)

Keywords: Java

Preface

It means that I'm not quiet at night, so I'll write a blog to slow down. Embarrassed

Read "Introduction to Algorithms" such a masterpiece, of course, we need to do some exercises. In addition to the theoretical thinking of practice questions and thinking questions, it is also inseparable from the practice of coding.

So, in each of the following chapters, I will try my best to sort out the Java code implementation of the algorithms involved in the chapters.

Two points search

Algorithm implementation

    package tech.jarry.learning.test.algorithms.binarysearch;
    
    public class BinarySearch {
    
        public static int binarySearch(int[] array, int target) {
            return binarySearch(array, target, 0, array.length - 1);
        }
    
        // Binary search requires the input linear table to be sequential
        public static int binarySearch(int[] array, int target, int startIndex, int endIndex) {
    
            if (endIndex > startIndex) {
                int middleIndex = (startIndex + endIndex) / 2;
    
                if (target < array[middleIndex]){
                    return binarySearch(array, target, startIndex, middleIndex);
                } else if (target > array[middleIndex]) {
                    return binarySearch(array, target, middleIndex + 1, endIndex);
                } else if (target == array[middleIndex]) {
                    return middleIndex;
                }
            }
    
            return -1;
        }
    }

Algorithm test

    package tech.jarry.learning.test.algorithms.binarysearch;
    
    public class BinarySearchTest {
    
        public static void main(String[] args) {
            int[] testArray = new int[] {3, 5, 7, 2, 4, 1, 5, 0, 9, 18 ,12};
    
            System.out.println(BinarySearch.binarySearch(testArray, 100));
        }
    }

Result output

-1

This means that no target data was found, you can change the target in the test class to another number.

Bubble sort

Algorithm implementation

    package tech.jarry.learning.test.algorithms.bubblesort;
    
    public class BubbleSort {
    
        public static int[] bubbleSort(int[] array) {
            for (int i = 0; i < array.length; i++){
                for (int j = i; j < array.length; j++) {
                    if (array[j] < array[i]) {
                        int temp = array[i];
                        array[i] = array[j];
                        array[j] = temp;
                    }
                }
            }
            return array;
        }
    }

Algorithm test

    package tech.jarry.learning.test.algorithms.bubblesort;
    
    import java.util.Arrays;
    
    public class BubbleSortTest {
        public static void main(String[] args) {
    
            int[] testArray = new int[] {3, 5, 7, 2, 4, 1, 5, 0, 9, 18 ,12};
    
            System.out.println(Arrays.toString(BubbleSort.bubbleSort(testArray)));
        }
    }

Result output

[0, 1, 2, 3, 4, 5, 5, 7, 9, 12, 18]

Insertion sort

Algorithm implementation

    package tech.jarry.learning.test.algorithms.insertsort;
    
    import java.util.Arrays;
    
    public class InsertionSort {
    
        public static int[]insertSort(int[] originArray) {
            // Start with the second element of the array (you can't compare the size of the first element with that of the first element)
            for (int j = 1; j < originArray.length; j++) {
                // Get the value of the current element
                int key = originArray[j];
                // Get the subscript of the previous element
                int i = j - 1;
                // Move the key value forward (every element greater than the key to be encountered will be moved back)
                while (i >= 0 && originArray[i] > key) {
                    originArray[i + 1] = originArray[i];
                     i = i - 1;
                }
                // The value of i+1 is not assigned until the originarray [i] < = key is encountered (the i+1 element has been moved backward and copied, that is, the value of i+1 position is saved in the i+2 position)
                originArray[i + 1] =key;
            }
    
            return originArray;
        }
    
        public static int[] insertSortProWithBinarySearch(int[] array) {
            // If the data is organized as an array, even if the binary search optimization is adopted, the movement of the underlying array elements will still cause the final time complexity to become n^2, rather than the expected n*lgn
            return null;
        }
    }

Algorithm test

    package tech.jarry.learning.test.algorithms.insertsort;
    
    import java.util.Arrays;
    
    public class InsertionSortTest {
        // test
        public static void main(String[] args) {
            int[] originArray = new int[]{9, 6, 4, 5, 8};
            int[] resultArray = InsertionSort.insertSort(originArray);
            System.out.println(Arrays.toString(resultArray));
        }
    }

Result output

[4, 5, 6, 8, 9]

Merge sort

Algorithm implementation

The implementation of this code may have more contents. On the one hand, it is due to the method extraction (the operation of extracting the creation of sentry), on the other hand, it is due to the addition of the implementation of merging and sorting without sentry mentioned in the exercises (in the mergeSort method, you can freely choose whether to use sentry or not).

    package tech.jarry.learning.test.algorithms.mergesort;
    
    import java.util.Arrays;
    
    /**
     * Merge sort
     */
    public class MergeSort {
    
        public static int[] mergeSort(int[] array) {
            return mergeSort(array, 0, array.length - 1);
        }
    
        public static int[] mergeSort(int[] array, int startIndex, int endIndex) {
            if (startIndex < endIndex) {
                int middleIndex = startIndex + (endIndex - startIndex) / 2;
                array = mergeSort(array, startIndex, middleIndex);
                array = mergeSort(array, middleIndex + 1, endIndex);
    
                // Use sentry to merge
    //            return merge(array, startIndex, middleIndex, endIndex);
                // Not for sentinels, merge
                return noSentinelMerge(array, startIndex, middleIndex, endIndex);
            }
    
            // If startIndex = endIndex, array has only one element
            return array;
        }
    
        private static int[] merge(int[] array, int startIndex, int middleIndex, int endIndex) {
            int[] sentinelLeftArray = createSentinelArray(array, startIndex, middleIndex);
            int[] sentinelRightArray = createSentinelArray(array, middleIndex + 1, endIndex);
    
            for (int i = 0, m = 0, n = 0; i < endIndex - startIndex + 1; i++) {
                if (sentinelLeftArray[m] < sentinelRightArray[n]) {
                    // Don't forget startIndex here, because different branches have different starting points
                    array[startIndex + i] = sentinelLeftArray[m++];
                } else {
                    array[startIndex + i] = sentinelRightArray[n++];
                }
                // You don't need to think about two integer. Max? Values, because the remaining elements of the last two arrays must be the two sentinel elements
            }
            return array;
        }
    
        private static int[] createSentinelArray(int[] array, int startIndex, int endIndex) {
            int length = endIndex - startIndex + 1;
            int[] sentinelArray = new int[length + 1];
            for (int i = 0; i < length; i++) {
                sentinelArray[i] = array[startIndex + i];
            }
            sentinelArray[endIndex - startIndex + 1] = Integer.MAX_VALUE;
            return sentinelArray;
        }
    
        // p. 22. Practise2.3-2 merge and sort without using Sentinels
        private static int[] noSentinelMerge(int[] array, int startIndex, int middleIndex, int endIndex) {
            int[] leftArray = createNonSentinelBranchArray(array, startIndex, middleIndex);
            int[] rightArray = createNonSentinelBranchArray(array, middleIndex + 1, endIndex);
    
            for (int i = 0, m = 0, n = 0; i < endIndex - startIndex + 1; i++) {
                if (leftArray[m] < rightArray[n]) {
                    array[startIndex + i] = leftArray[m++];
                    if (m == leftArray.length) {
                        // Copy all the remaining elements of rightArray to the corresponding position of array
                        array = branchArray2Array(array, startIndex + i + 1, rightArray, n);
                        break;
                    }
                } else {
                    array[startIndex + i] = rightArray[n++];
                    if (n == rightArray.length) {
                        // Copy all the remaining elements of leftArray to the corresponding position of array
                        array = branchArray2Array(array, startIndex + i + 1, leftArray, m);
                        break;
                    }
                }
                // You don't need to think about two integer. Max? Values, because the remaining elements of the last two arrays must be the two sentinel elements
            }
            return array;
        }
    
        private static int[] createNonSentinelBranchArray(int[] array, int startIndex, int endIndex) {
            int length = endIndex - startIndex + 1;
            int[] branchArray = new int[length];
            for (int i = 0; i < length; i++) {
                branchArray[i] = array[startIndex + i];
            }
            return branchArray;
        }
    
        private static int[] branchArray2Array(int[] array, int targetIndex, int[] branchArray, int startIndex) {
            while (startIndex < branchArray.length) {
                array[targetIndex++] = branchArray[startIndex++];
            }
            return array;
        }
    
        // Due to some conditions (such as insufficient memory space), data can be saved directly to the hard disk. Instead of being stored in an array of memory
        private static void merge2Disk(int[] array, int startIndex, int middleIndex, int endIndex){
            int[] sentinelLeftArray = createSentinelArray(array, startIndex, middleIndex);
            int[] sentinelRightArray = createSentinelArray(array, middleIndex + 1, endIndex);
    
            for (int i = 0, m = 0, n = 0; i < endIndex - startIndex + 1; i++) {
                if (sentinelLeftArray[m] < sentinelRightArray[n]) {
                    Disk.store(sentinelLeftArray[m++]);
                } else {
                    Disk.store(sentinelRightArray[n++]);
                }
                // You don't need to think about two integer. Max? Values, because the remaining elements of the last two arrays must be the two sentinel elements
            }
        }
    
        // test_creatreSentinelArray
        public static void main(String[] args) {
            int[] testArray = new int[] {3, 5, 7, 2, 4, 1, 5, 0};
            System.out.println(Arrays.toString(createSentinelArray(testArray, 0 , 2)));
        }
    }

Add: the Disk class involved in the above code

The reason why this hard disk operation is added to merge sorting is that I do this problem and remember an interview question I met a long time ago. That is, how to use 1G space to sort 8G data. The answer is to sort by merging (the principle was stated at that time, but the whiteboard was not written well).

package tech.jarry.learning.test.algorithms.mergesort;
    
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
    
    /**
     * Simulate real hard disk to store and print data
     */
    public class Disk {
    
        private static List<Integer> diskIntegerInstance = new ArrayList<>();
    
        public static void store(int element) {
            diskIntegerInstance.add(element);
        }
    
        public static void printAll() {
            Iterator<Integer> integerIterator = diskIntegerInstance.iterator();
            while (integerIterator.hasNext()) {
                System.out.println(integerIterator.next());
            }
        }
    
    }

Algorithm test

    package tech.jarry.learning.test.algorithms.mergesort;
    
    import java.util.Arrays;
    
    public class MergeSortTest {
    
        public static void main(String[] args) {
            int[] testArray = new int[] {3, 5, 7, 2, 4, 1, 5, 0, 9, 18 ,12};
            // 3, 5, 7, 2, 4, 1, 5, 0, 9, 18 ,12
            // correct result: [0, 1, 2, 3, 4, 5, 5, 7, 9, 12, 18]
            int[] resultArray = MergeSort.mergeSort(testArray);
            System.out.println(Arrays.toString(resultArray));
        }
    }

Result output

[0, 1, 2, 3, 4, 5, 5, 7, 9, 12, 18]

Determine the sum of the two numbers as a fixed value

This problem exists in leetcode, and previous blogs also have corresponding analysis. Even leetcode has the problem of finding the sum of three numbers as a definite value.

Algorithm implementation

    package tech.jarry.learning.ch2.algorithms.twosum;
    
    import tech.jarry.learning.ch2.algorithms.mergesort.MergeSort;
    
    public class TwoSum {
    
        // In the topic, only the implementation is required to determine whether it exists, without returning the corresponding index. Otherwise, you need to remove the same index and modify the return value of binarySearch
        public static boolean twoSum(int[] array, int target) {
            array = MergeSort.mergeSort(array);
    
            for (int i = 0; i < array.length; i++) {
                int branchTarget = target - array[i];
    
                // The time complexity of binary search is lgn
                if (binarySearch(array, branchTarget)) {
                    return true;
                }
            }
            return false;
        }
    
        private static boolean binarySearch(int[] array, int target) {
            return binarySearch(array, target, 0, array.length - 1);
        }
    
        private static boolean binarySearch(int[] array, int target, int startIndex, int endIndex) {
            if (endIndex > startIndex) {
                int middleIndex = (endIndex + startIndex) / 2;
                if (target < array[middleIndex]) {
                    return binarySearch(array, target, startIndex, middleIndex);
                } else if (target > array[middleIndex]) {
                    return binarySearch(array, target, middleIndex + 1, endIndex);
                } else if (target == array[middleIndex]) {
                    return true;
                }
            }
    
            return false;
        }
    }

Algorithm test

    package tech.jarry.learning.test.algorithms.twosum;
    
    public class TwoSumTest {
    
        public static void main(String[] args) {
            int[] testArray = new int[] {3, 5, 7, 2, 4, 1, 5, 0, 9, 18 ,12};
            int target = 80;
            System.out.println(TwoSum.twoSum(testArray, target));
        }
    }

Result output

false

Because the demo in the book only requires whether the output exists or not, and the topic similar to leetcode requires the index of two elements to be returned. Interested friends, you can see my blog about the solution to the sum of two numbers of leetcode.

summary

In fact, the demo of the algorithm in this chapter is relatively easy to implement. It's more about finding the feeling of implementing the algorithm.

If there's something wrong with the code, or if you have any doubts, you can send me a private message or @ me.

I wish to make progress with you.

Posted by Scriptor on Sat, 22 Feb 2020 20:42:45 -0800