算法——十大排序算法(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);

	}

}

堆排序-x

在这里插入代码片

参考链接:堆排序

计数排序

传统的计数排序

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

在这里插入代码片

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

猜你喜欢

转载自blog.csdn.net/qq_35655602/article/details/107323609