算法——十大排序算法(java版本实现)

十大排序算法脑图:
排序算法

在这里插入图片描述

冒泡排序

传统的冒泡排序

public static void sort(int array[]) {
    for (int i = 0; i < array.length - 1; i++) {
        for (int j = 0; j < array.length - i - 1; j++) {
            int temp = 0;
            if (array[j] > array[j + 1]) {
                temp = array[j];
                array[j] = array[j + 1];
                array[j + 1] = temp;
            }
        }
        if (isSorted){
            break;
        }
    }
}

优化一:

问题:经过多轮排序后,数列已经有序了,剩下的几轮排序就不必执行了,可以提前结束
解决:判断数列是否已经有序,并做出标记
如果本轮排序中有元素交换,则说明数列无序,如果没有元素交换,则说明数列已经有序,直接跳出大循环。

public static void sort(int array[]) {
    for (int i = 0; i < array.length - 1; i++) {
        //有序标记,每一轮的初始值都是true
        boolean isSorted = true;
        for (int j = 0; j < array.length - i - 1; j++) {
            int temp = 0;
            if (array[j] > array[j + 1]) {
                temp = array[j];
                array[j] = array[j + 1];
                array[j + 1] = temp;
                //因为有元素进行交换,所以不是有序的,标记变为false
                isSorted = false;

            }
        }
        if (isSorted){
            break;
        }
    }
}

优化二:

问题:后半部分元素中的最小值大于前半部分元素的最大值,即右边的许多元素已经有序了
解决:对数列有序区的界定
每一轮排序后,记录下来最后一次元素交换的位置,该位置即为无序数列的边界,再往后就是有序区了

public static void sort_2(int array[]) {
    for (int i = 0; i < array.length - 1; i++) {
        //有序标记,每一轮的初始值都是true
        boolean isSorted = true;
        //无序数列的边界,每次比较只需要比到这里为止
        int sortBorder = array.length -1;
        for (int j = 0; j < sortBorder; j++) {
            int temp = 0;
            if (array[j] > array[j + 1]) {
                temp = array[j];
                array[j] = array[j + 1];
                array[j + 1] = temp;
                //因为有元素进行交换,所以不是有序的,标记变为false
                isSorted = false;
                //把无序数列的边界更新为最后一次交换元素位置
                sortBorder = j;
            }
        }
        if (isSorted){
            break;
        }
    }
}

参考链接:冒泡排序

鸡尾酒排序

参考链接:鸡尾酒排序

选择排序

public class select_sort {
    public static void selctionSort(int[] arr){
        if (arr == null || arr.length < 2){
            return;
        }
        for (int i = 0; i < arr.length; i++) {
            int minIndex = i;
            for (int j = i + 1; j < arr.length; j++) {
                minIndex = arr[j] < arr[minIndex] ? j : minIndex;
            }
            swap(arr,i,minIndex);
        }
    }
    public static void swap(int[] arr,int i,int j){
/*
        arr[i] = arr[i] ^ arr[j];
        arr[j] = arr[i] ^ arr[j];
        arr[i] = arr[i] ^ arr[j];

*/
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

插入排序

/**
 *  插入排序
 *  一堆有序的扑克牌,插入一张牌
 */
public class Insert_Sort {
    public static void insertionSort(int[] arr){
        if (arr == null || arr.length < 2){
            return;
        }
        for (int i = 1; i < arr.length; i++) {
            for (int j = i - 1; j >= 0 && arr[j] > arr[j + 1]; j--) {
                swap(arr,j,j+1);
            }
        }
    }
    public static void swap(int[] arr,int i,int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

希尔排序-x

在这里插入代码片

快速排序

在这里插入图片描述

递归实现–双边循环法、单边循环法

package sort;/**
 * Copyright (C), 2019-2020
 * author  candy_chen
 * date   2020/7/3 10:50
 * version 1.0
 * Description: 快速排序
 *
 * partition()  分治法(双边循环法)
 * partitionV2()  分治法(单边循环法)
 */

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

/**
 *
 */
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);
    }
    /**
     * 非递归实现快排
     * 转换成栈的实现,在栈中存储每一次方法调用的参数
     * 该方法引入一个存储Map类型元素的栈,用于存储每一次交换时的起始下标和结束下标
     * 每一次循环,都会让栈顶元素出栈,通过partition方法进行分治,并且按照基准元素的位置分成左右两部分,左右两部分再分别入栈。
     * 当栈位空时,说明排序完毕,退出循环。
     */
    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);
            }
        }
    }

    /**
     * partition方法实现了元素的交换,让数列中的元素依据自身大小,分别交换到基准元素的左右两边
     * 分治 (双边循环法)
     * @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];
        //mark代表小于基准元素的区域边界
        int mark = startIndex;
        //从基准元素的下一个位置开始遍历数组
        for (int i = startIndex+1; i < endIndex; i++) {
            //如果小于基准元素,则一,把mark指针右移1位,因为小于pivot的区域边界增大了1;
            // 二,让最新遍历到的元素和mark指针所在位置的元素交换,因为最新遍历的元素归属于小于pivot的区域
            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));
    }
}

非递归实现快速排序-x

在这里插入代码片

参考链接:快速排序

归并排序

package basic_class_01;

import java.util.Arrays;

public class Code_05_MergeSort {

	public static void mergeSort(int[] arr) {
		if (arr == null || arr.length < 2) {
			return;
		}
		mergeSort(arr, 0, arr.length - 1);
	}

	public static void mergeSort(int[] arr, int l, int r) {
		if (l == r) {
			return;
		}
		int mid = l + ((r - l) >> 1);
		mergeSort(arr, l, mid);
		mergeSort(arr, mid + 1, r);
		merge(arr, l, mid, r);
	}

	public static void merge(int[] arr, int l, int m, int r) {
		int[] help = new int[r - l + 1];
		int i = 0;
		int p1 = l;
		int p2 = m + 1;
		while (p1 <= m && p2 <= r) {
			help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
		}
		while (p1 <= m) {
			help[i++] = arr[p1++];
		}
		while (p2 <= r) {
			help[i++] = arr[p2++];
		}
		for (i = 0; i < help.length; i++) {
			arr[l + i] = help[i];
		}
	}

	// for test
	public static void comparator(int[] arr) {
		Arrays.sort(arr);
	}

	// for test
	public static int[] generateRandomArray(int maxSize, int maxValue) {
		int[] arr = new int[(int) ((maxSize + 1) * Math.random())];
		for (int i = 0; i < arr.length; i++) {
			arr[i] = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());
		}
		return arr;
	}

	// for test
	public static int[] copyArray(int[] arr) {
		if (arr == null) {
			return null;
		}
		int[] res = new int[arr.length];
		for (int i = 0; i < arr.length; i++) {
			res[i] = arr[i];
		}
		return res;
	}

	// for test
	public static boolean isEqual(int[] arr1, int[] arr2) {
		if ((arr1 == null && arr2 != null) || (arr1 != null && arr2 == null)) {
			return false;
		}
		if (arr1 == null && arr2 == null) {
			return true;
		}
		if (arr1.length != arr2.length) {
			return false;
		}
		for (int i = 0; i < arr1.length; i++) {
			if (arr1[i] != arr2[i]) {
				return false;
			}
		}
		return true;
	}

	// for test
	public static void printArray(int[] arr) {
		if (arr == null) {
			return;
		}
		for (int i = 0; i < arr.length; i++) {
			System.out.print(arr[i] + " ");
		}
		System.out.println();
	}

	// for test
	public static void main(String[] args) {
		int testTime = 500000;
		int maxSize = 100;
		int maxValue = 100;
		boolean succeed = true;
		for (int i = 0; i < testTime; i++) {
			int[] arr1 = generateRandomArray(maxSize, maxValue);
			int[] arr2 = copyArray(arr1);
			mergeSort(arr1);
			comparator(arr2);
			if (!isEqual(arr1, arr2)) {
				succeed = false;
				printArray(arr1);
				printArray(arr2);
				break;
			}
		}
		System.out.println(succeed ? "Nice!" : "Fucking fucked!");

		int[] arr = generateRandomArray(maxSize, maxValue);
		printArray(arr);
		mergeSort(arr);
		printArray(arr);

	}

}

public class mergeSort {
    public static void mergeSort(int[] array,int left,int right){
        if (right <= left) return;
        int mid = (left + right) >> 1;//  (left + right) / 2

        mergeSort(array, left, mid);
        mergeSort(array,mid + 1,right);
        merge(array,left,mid,right);
    }

    private static void merge(int[] arr, int left, int mid, int right) {
        int[] temp = new int[right - left + 1];
        int i = left,j = mid + 1,k = 0;

        //两个数组要合并在一起的数组
        while (i <= mid && j <= right){
            temp[k++] = arr[i] <= arr[j] ? arr[i++] : arr[j++];
        }
        while (i <= mid) temp[k++] = arr[i++];
        while (j <= right) temp[k++] = arr[j++];

        for (int p = 0; p < temp.length; p++) {
            arr[left + p] = temp[p];
        }
        //也可以用System.arraycopy(a,start1,b,start2,length)
    }
}

堆排序

public class heapSort {
    static void heapify(int[] array,int length,int i){
        int left = 2 * i + 1,right = 2 * i + 2;
        int largest = i;

        if (left < length && array[left] > array[largest]) {
            largest = left;
        }
        if (right < length && array[right] > array[largest]) {
            largest = right;
        }
        if (largest != i){
            int temp = array[i];
            array[i] = array[largest];
            array[largest] = temp;
            heapify(array, length,largest);
        }
    }
    public static void heapSort(int[] array){
        if (array.length == 0) return;

        int length = array.length;
        for (int i = length / 2 - 1;i >= 0; i--) {
            heapify(array,length,i);
        }
        for (int i = length - 1; i >= 0;i--){
            int temp = array[0];
            array[0] = array[i];
            array[i] = temp;
            heapify(array,i,0);
        }
    }

}

参考链接:堆排序

计数排序

传统的计数排序

1.先得到数列的最大值;
2.根据数列最大值确定统计数组的长度,数组长度为:输入数列的最大值+1;
3.遍历数列,填充统计数组;
4. 遍历统计数组,输出结果

public static int[] countSort(int[] array) {
    //1.得到数列的最大值
    int max = array[0];
    for (int i = 0; i < array.length; i++) {
        if (array[i] > max) {
            max = array[i];
        }
    }
    //2.根据数列最大值确定统计数组的长度
    int[] countArray = new int[array.length];
    //3.遍历数列,填充统计数组
    for (int i = 0; i < array.length; i++) {
        countArray[array[i]]++;//每一个整数按照其值对号入座,同时对应数组下标的元素进行加1操作
    }
    //4.遍历统计数组,输出结果
    int index = 0;
    int[] sortedArray = new int[array.length];
    for (int i = 0; i < array.length; i++) {
        for (int j = 0; j < countArray[i]; j++) {
            sortedArray[index++] = i;
        }
    }
    return sortedArray;

}

计数排序优化

问题:最大数和最小数相差较小的时候,用最大值决定统计数组的长度容易浪费空间
解决

  1. 数组的长度为数列最大值-最小值+1
  2. 数列的最小值作为一个偏移量,用于计算整数在统计数组中的下标
public static int[] countSort2(int[] array){
    //1.得到数列的最大值和最小值,并计算出差值d
    int max = array[0];
    int min = array[0];
    for (int i=0;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;
}

参考链接:计数排序

桶排序

桶排序:每一个桶代表的一个区间范围,可以承载一个或对个元素
桶的数量
桶的区间跨度

package sort;/**
 * Copyright (C), 2019-2020
 * author  candy_chen
 * date   2020/7/13 19:03
 * version 1.0
 * Description: 测试
 */

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

/**
 *桶排序
 * 所有的桶都保存在ArrayList集合中,每一个桶都被定义成一个链表LinkedList<Double>,这样便于在尾部进行插入元素
 */
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> linkedList: bucketList){
            for (double element:linkedList) {
                sortedArray[index] = element;
                index++;
            }
        }
        return sortedArray;
    }

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

参考链接:桶排序

基数排序-x

在这里插入代码片

说明:根据网络资料进行搜索学习理解整理 若有侵权联系作者

posted @ 2020-07-13 19:43  your_棒棒糖  阅读(47)  评论(0编辑  收藏  举报