算法——十大排序算法(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
- 数列的最小值作为一个偏移量,用于计算整数在统计数组中的下标
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
在这里插入代码片
说明:根据网络资料进行搜索学习理解整理 若有侵权联系作者