《漫画算法》源码整理-5 排序算法

Posted GarfieldEr007

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《漫画算法》源码整理-5 排序算法相关的知识,希望对你有一定的参考价值。

冒泡排序

import java.util.Arrays;

public class BubbleSort 

    public static void sort(int array[])
    
        int tmp  = 0;
        //记录最后一次交换的位置
        int lastExchangeIndex = 0;
        //无序数列的边界,每次比较只需要比到这里为止
        int sortBorder = array.length - 1;
        for(int i = 0; i < array.length; i++)
        
            //有序标记,每一轮的初始是true
            boolean isSorted = true;

            for(int j = 0; j < sortBorder; j++)
            
                if(array[j] > array[j+1])
                
                    tmp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = tmp;
                    //有元素交换,所以不是有序,标记变为false
                    isSorted = false;
                    //把无序数列的边界更新为最后一次交换元素的位置
                    lastExchangeIndex = j;
                
            
            sortBorder = lastExchangeIndex;
            if(isSorted)
                break;
            
        
    

    public static void main(String[] args)
        int[] array = new int[]3,4,2,1,5,6,7,8;
        sort(array);
        System.out.println(Arrays.toString(array));
    

鸡尾酒排序

import java.util.Arrays;

public class CockTailSort 

    public static void sort(int array[])
    
        int tmp  = 0;
        for(int i=0; i<array.length/2; i++)
        
            //有序标记,每一轮的初始是true
            boolean isSorted = true;
            //奇数轮,从左向右比较和交换
            for(int j=i; j<array.length-i-1; j++)
            
                if(array[j] > array[j+1])
                
                    tmp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = tmp;
                    //有元素交换,所以不是有序,标记变为false
                    isSorted = false;
                
            
            if(isSorted)
                break;
            

            //偶数轮之前,重新标记为true
            isSorted = true;
            //偶数轮,从右向左比较和交换
            for(int j=array.length-i-1; j>i; j--)
            
                if(array[j] < array[j-1])
                
                    tmp = array[j];
                    array[j] = array[j-1];
                    array[j-1] = tmp;
                    //有元素交换,所以不是有序,标记变为false
                    isSorted = false;
                
            
            if(isSorted)
                break;
            
        
    

    public static void main(String[] args)
        int[] array = new int[]2,3,4,5,6,7,8,1;
        sort(array);
        System.out.println(Arrays.toString(array));
    

快速排序

import java.util.Arrays;

public class QuickSort 

    public static void quickSort(int[] arr, int startIndex, int endIndex) 
        // 递归结束条件:startIndex大等于endIndex的时候
        if (startIndex >= endIndex) 
            return;
        
        // 得到基准元素位置
        int pivotIndex = partition(arr, startIndex, endIndex);
        // 根据基准元素,分成两部分递归排序
        quickSort(arr, startIndex, pivotIndex - 1);
        quickSort(arr, pivotIndex + 1, endIndex);
    

    /**
     * 分治(双边循环法)
     * @param arr     待交换的数组
     * @param startIndex    起始下标
     * @param endIndex    结束下标
     */
    private static int partition(int[] arr, int startIndex, int endIndex) 
        // 取第一个位置的元素作为基准元素(也可以选择随机位置)
        int pivot = arr[startIndex];
        int left = startIndex;
        int right = endIndex;

        while( left != right) 
            //控制right指针比较并左移
            while(left<right && arr[right] > pivot)
                right--;
            
            //控制left指针比较并右移
            while( left<right && arr[left] <= pivot) 
                left++;
            
            //交换left和right指向的元素
            if(left<right) 
                int p = arr[left];
                arr[left] = arr[right];
                arr[right] = p;
            
        

        //pivot和指针重合点交换
        arr[startIndex] = arr[left];
        arr[left] = pivot;

        return left;
    

    /**
     * 分治(单边循环法)
     * @param arr     待交换的数组
     * @param startIndex    起始下标
     * @param endIndex    结束下标
     */
    private static int partitionV2(int[] arr, int startIndex, int endIndex) 
        // 取第一个位置的元素作为基准元素(也可以选择随机位置)
        int pivot = arr[startIndex];
        int mark = startIndex;

        for(int i=startIndex+1; i<=endIndex; i++)
            if(arr[i]<pivot)
                mark ++;
                int p = arr[mark];
                arr[mark] = arr[i];
                arr[i] = p;
            
        

        arr[startIndex] = arr[mark];
        arr[mark] = pivot;
        return mark;
    

    public static void main(String[] args) 
        int[] arr = new int[] 4,4,6,5,3,2,8,1;
        quickSort(arr, 0, arr.length-1);
        System.out.println(Arrays.toString(arr));
    

使用栈快速排序

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;

public class QuickSortWithStack 

    public static void quickSort(int[] arr, int startIndex, int endIndex) 
        // 用一个集合栈来代替递归的函数栈
        Stack<Map<String, Integer>> quickSortStack = new Stack<Map<String, Integer>>();
        // 整个数列的起止下标,以哈希的形式入栈
        Map rootParam = new HashMap();
        rootParam.put("startIndex", startIndex);
        rootParam.put("endIndex", endIndex);
        quickSortStack.push(rootParam);

        // 循环结束条件:栈为空时结束
        while (!quickSortStack.isEmpty()) 
            // 栈顶元素出栈,得到起止下标
            Map<String, Integer> param = quickSortStack.pop();
            // 得到基准元素位置
            int pivotIndex = partition(arr, param.get("startIndex"), param.get("endIndex"));
            // 根据基准元素分成两部分, 把每一部分的起止下标入栈
            if(param.get("startIndex") <  pivotIndex -1)
                Map<String, Integer> leftParam = new HashMap<String, Integer>();
                leftParam.put("startIndex",  param.get("startIndex"));
                leftParam.put("endIndex", pivotIndex -1);
                quickSortStack.push(leftParam);
            
            if(pivotIndex + 1 < param.get("endIndex"))
                Map<String, Integer> rightParam = new HashMap<String, Integer>();
                rightParam.put("startIndex", pivotIndex + 1);
                rightParam.put("endIndex", param.get("endIndex"));
                quickSortStack.push(rightParam);
            
        
    

    /**
     * 分治(单边循环法)
     * @param arr     待交换的数组
     * @param startIndex    起始下标
     * @param endIndex    结束下标
     */
    private static int partition(int[] arr, int startIndex, int endIndex) 
        // 取第一个位置的元素作为基准元素(也可以选择随机位置)
        int pivot = arr[startIndex];
        int mark = startIndex;

        for(int i=startIndex+1; i<=endIndex; i++)
            if(arr[i]<pivot)
                mark ++;
                int p = arr[mark];
                arr[mark] = arr[i];
                arr[i] = p;
            
        

        arr[startIndex] = arr[mark];
        arr[mark] = pivot;
        return mark;
    

    public static void main(String[] args) 
        int[] arr = new int[] 4,7,6,5,3,2,8,1;
        quickSort(arr, 0, arr.length-1);
        System.out.println(Arrays.toString(arr));
    


堆排序

import java.util.Arrays;

public class HeapSort 

    /**
     * 下沉调整
     * @param array     待调整的堆
     * @param parentIndex    要下沉的父节点
     * @param length    堆的有效大小
     */
    public static void downAdjust(int[] array, int parentIndex, int length) 
        // temp保存父节点值,用于最后的赋值
        int temp = array[parentIndex];
        int childIndex = 2 * parentIndex + 1;
        while (childIndex < length) 
            // 如果有右孩子,且右孩子大于左孩子的值,则定位到右孩子
            if (childIndex + 1 < length && array[childIndex + 1] > array[childIndex]) 
                childIndex++;
            
            // 如果父节点大于等于任何一个孩子的值,直接跳出
            if (temp >= array[childIndex])
                break;
            //无需真正交换,单向赋值即可
            array[parentIndex] = array[childIndex];
            parentIndex = childIndex;
            childIndex = 2 * childIndex + 1;
        
        array[parentIndex] = temp;
    

    /**
     * 堆排序(升序)
     * @param array     待调整的堆
     */
    public static void heapSort(int[] array) 
        // 1.把无序数组构建成最大堆。
        for (int i = (array.length-2)/2; i >= 0; i--) 
            downAdjust(array, i, array.length);
        
        System.out.println(Arrays.toString(array));
        // 2.循环交换集合尾部元素到堆顶,并调节堆产生新的堆顶。
        for (int i = array.length - 1; i > 0; i--) 
            // 最后一个元素和第一元素进行交换
            int temp = array[i];
            array[i] = array[0];
            array[0] = temp;
            // 下沉调整最大堆
            downAdjust(array, 0, i);
        
    

    public static void main(String[] args) 
        int[] arr = new int[] 1,3,2,6,5,7,8,9,10,0;
        heapSort(arr);
        System.out.println(Arrays.toString(arr));
    

桶排序

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;

public class BucketSort 

    public static double[] bucketSort(double[] array)

        //1.得到数列的最大值和最小值,并算出差值d
        double max = array[0];
        double min = array[0];
        for(int i=1; i<array.length; i++) 
            if(array[i] > max) 
                max = array[i];
            
            if(array[i] < min) 
                min = array[i];
            
        
        double d = max - min;

        //2.初始化桶
        int bucketNum = array.length;
        ArrayList<LinkedList<Double>> bucketList = new ArrayList<LinkedList<Double>>(bucketNum);
        for(int i = 0; i < bucketNum; i++)
            bucketList.add(new LinkedList<Double>());
        

        //3.遍历原始数组,将每个元素放入桶中
        for(int i = 0; i < array.length; i++)
            int num = (int)((array[i] - min)  * (bucketNum-1) / d);
            bucketList.get(num).add(array[i]);
        

        //4.对每个桶内部进行排序
        for(int i = 0; i < bucketList.size(); i++)
            //JDK底层采用了归并排序或归并的优化版本
            Collections.sort(bucketList.get(i));
        

        //5.输出全部元素
        double[] sortedArray = new double[array.length];
        int index = 0;
        for(LinkedList<Double> list : bucketList)
            for(double element : list)
                sortedArray[index] = element;
                index++;
            
        
        return sortedArray;
    

    public static void main(String[] args) 
        double[] array = new double[] 4.12,6.421,0.0023,3.0,2.123,8.122,4.12, 10.09;
        double[] sortedArray = bucketSort(array);
        System.out.println(Arrays.toString(sortedArray));
    

计数排序

import java.util.Arrays;

public class CountSort 

    public static int[] countSort(int[] array) 
        //1.得到数列的最大值
        int max = array[0];
        for(int i=1; i<array.length; i++)
            if(array[i] > max)
                max = array[i];
            
        
        //2.根据数列最大值确定统计数组的长度
        int[] countArray = new int[max+1];
        //3.遍历数列,填充统计数组
        for(int i=0; i<array.length; i++)
            countArray[array[i]]++;
        
        //4.遍历统计数组,输出结果
        int index = 0;
        int[] sortedArray = new int[array.length];
        for(int i=0; i<countArray.length; i++)
            for(int j=0; j<countArray[i]; j++)
                sortedArray[index++] = i;
            
        
        return sortedArray;
    

    public static int[] countSortV2(int[] array) 
        //1.得到数列的最大值和最小值,并算出差值d
        int max = array[0];
        int min = array[0];
        for(int i=1; i<array.length; i++) 
            if(array[i] > max) 
                max = array[i];
            
            if(array[i] < min) 
                min = array[i];
            
        
        int d = max - min;
        //2.创建统计数组并统计对应元素个数
        int[] countArray = new int[d+1];
        for(int i=0; i<array.length; i++) 
            countArray[array[i]-min]++;
        
        //3.统计数组做变形,后面的元素等于前面的元素之和
        for(int i=1;i<countArray.length;i++) 
            countArray[i] += countArray[i-1];
        
        //4.倒序遍历原始数列,从统计数组找到正确位置,输出到结果数组
        int[] sortedArray = new int[array.length];
        for(int i=array.length-1;i>=0;i--) 
            sortedArray[countArray[array[i]-min]-1]=array[i];
            countArray[array[i]-min]--;
        
        return sortedArray;
    

    public static void main(String[] args) 
        int[] array = new int[] 4,4,6,5,3,2,8,1,7,5,6,0,10;
        int[] sortedArray = countSort(array);
        System.out.println(Arrays.toString(sortedArray));

        array = new int[] 95,94,91,98,99,90,99,93,91,92;
        sortedArray = countSort(array);
        System.out.println(Arrays.toString(sortedArray));
    

选择排序

import java.util.Arrays;

public class SelectionSort 
    public static void selectionSort(int[] array) 
        for (int i = 0; i < array.length - 1; i++) 
            int minIndex = i;
            for (int j = i + 1; j < array.length; j++) 
                if (array[j] < array[minIndex]) 
                    minIndex = j;
                
            
            if (i != minIndex) 
                int temp = array[i];
                array[i] = array[minIndex];
                array[minIndex] = temp;
            
        
    

    public static void main(String[] args) 
        int[] array = new int[] 3, 4, 2, 1, 5, 6, 7, 8, 30, 50, 1, 33, 24, 5, -4, 7, 0;
        selectionSort(array);
        System.out.println(Arrays.toString(array));
    


插入排序

import java.util.Arrays;

public class InsertionSort 
    public static void insertSort(int[] array) 
        for (int i = 1; i < array.length; i++) 
            int insertValue = array[i];
            int j = i - 1;
            //从右向左比较元素的同时,进行元素复制
            for (; (j >= 0) && (insertValue < array[j]); j--) 
                array[j + 1] = array[j];
            
            //insertValue的值插入适当位置
            array[j + 1] = insertValue;
        
    

    public static void main(String[] args) 
        int[] array =  12, 1, 3, 46, 5, 0, -3, 12, 35, 16 ;
        insertSort(array);
        System.out.println(Arrays.toString(array));
    


希尔排序

import java.util.Arrays;

public class ShellSort 
    public static void shellSort(int[] array) 
        //希尔排序的增量
        int d = array.length;

        while (d > 1) 
            //使用希尔增量的方式,即每次折半
            d = d / 2;
            for (int x = 0; x < d; x++) 
                for (int i = x + d; i < array.length; i = i + d) 
                    int temp = array[i];
                    int j;
                    for (j = i - d; (j >= 0) && (array[j] > temp); j = j - d) 
                        array[j + d] = array[j];
                    
                    array[j + d] = temp;
                
            
        
    

    public static void main(String[] args) 
        int[] array =  5, 3, 9, 12, 6, 1, 7, 2, 4, 11, 8, 10 ;
        shellSort(array);
        System.out.println(Arrays.toString(array));
    


归并排序

import java.util.Arrays;

public class MergeSort 
    public static void mergeSort(int[] array, int start, int end) 
        if (start < end) 
            //折半成两个小集合,分别进行递归
            int mid = (start + end) / 2;
            mergeSort(array, start, mid);
            mergeSort(array, mid + 1, end);
            //把两个有序小集合,归并成一个大集合
            merge(array, start, mid, end);
        
    

    private static void merge(int[] array, int start, int mid, int end) 
        //开辟额外大集合,设置指针
        int[] tempArray = new int[end - start + 1];
        int p1 = start;
        int p2 = mid + 1;
        int p = 0;
        //比较两个小集合的元素,依次放入大集合
        while ((p1 <= mid) && (p2 <= end)) 
            if (array[p1] <= array[p2]) 
                tempArray[p++] = array[p1++];
            
            else 
                tempArray[p++] = array[p2++];
            
        
        //左侧小集合还有剩余,依次放入大集合尾部
        while (p1 <= mid) 
            tempArray[p++] = array[p1++];
        
        //右侧小集合还有剩余,依次放入大集合尾部
        while (p2 <= end) 
            tempArray[p++] = array[p2++];
        
        //把大集合的元素复制回原数组
        for (int i = 0; i < tempArray.length; i++) 
            array[i + start] = tempArray[i];
        
    

    public static void main(String[] args) 
        int[] array =  5, 8, 6, 3, 9, 2, 1, 7 ;
        mergeSort(array, 0, array.length - 1);
        System.out.println(Arrays.toString(array));
    


基数排序

import java.util.Arrays;


public class RadixSort 
    //ascii码的取值范围
    public static final int ASCII_RANGE = 128;

    public static String[] radixSort(String[] array, int maxLength) 
        //排序结果数组,用于存储每一次按位排序的临时结果
        String[] sortedArray = new String[array.length];
        //从个位开始比较,一直比较到最高位
        for (int k = maxLength - 1; k >= 0; k--) 
            //计数排序的过程,分成三步:
            //1.创建辅助排序的统计数组,并把待排序的字符对号入座,
            //这里为了代码简洁,直接使用ascii码范围作为数组长度
            int[] count = new int[ASCII_RANGE];
            for (int i = 0; i < array.length; i++) 
                int index = getCharIndex(array[i], k);
                count[index]++;
            
            //2.统计数组做变形,后面的元素等于前面的元素之和
            for (int i = 1; i < count.length; i++) 
                count[i] = count[i] + count[i - 1];
            
            //3.倒序遍历原始数列,从统计数组找到正确位置,输出到结果数组
            for (int i = array.length - 1; i >= 0; i--) 
                int index = getCharIndex(array[i], k);
                int sortedIndex = count[index] - 1;
                sortedArray[sortedIndex] = array[i];
                count[index]--;
            
            //下一轮排序需要以上一轮的排序结果为基础,因此把结果复制给array
            array = sortedArray.clone();
        
        return array;
    

    //获取字符串第k位字符所对应的ascii码序号
    private static int getCharIndex(String str, int k) 
        //如果字符串长度小于k,直接返回0,相当于给不存在的位置补0
        if (str.length() < (k + 1)) 
            return 0;
        
        return str.charAt(k);
    

    public static void main(String[] args) 
        String[] array =  "qd", "abc", "qwe", "hhh", "a", "cws", "ope" ;
        System.out.println(Arrays.toString(radixSort(array, 3)));
    

以上是关于《漫画算法》源码整理-5 排序算法的主要内容,如果未能解决你的问题,请参考以下文章

《漫画算法》源码整理-7

《漫画算法》源码整理-6

《漫画算法》源码整理-4 大顶堆 小顶堆 优先队列

《漫画算法2》源码整理-9 股票交易最大收益

《漫画算法2》源码整理-1 二分查找树 AVL树 红黑树

《漫画算法2》源码整理-7 第K大的数字