java数组排序算法
快速排序
分治法:比大小,再分区
- 从数组中取出一个数,作为基准数
- 分区:将比这个数大或等于的数全放到他的右边,小于他的数全放到他的左边
- 再对左右区间重复第二步,直到各区间只有一个数
package com.array.arraysort;
import java.util.Arrays;
// 分治法:比大小,再分区
public class QuickSort {
public static void main(String[] args) {
int[] arr = {2,1,34,5,7,56,3,23};
// 调用工具类,进行快排 传入数组,起始位置,结束位置
quick(arr,0,arr.length-1);
System.out.println(Arrays.toString(arr));
}
public static void quick(int[] arr, int start, int end) {
// 找出分左右两区的索引位置,然后对左右两区进行递归调用
if (start<end){
int index = getIndex(arr,start,end);
quick(arr,start,index-1);
quick(arr,index+1,end);
}
}
private static int getIndex(int[] arr,int start,int end){
int i = start;
int j = end;
int x = arr[i]; //基本数
while(i<j){
// 由后往前找比他小的数,将此数填到前一个坑中
while(i<j&&arr[j]>=x){
j--;
}
if(i<j){
arr[i] = arr[j];
i++;
}
// 由前往后找比他大或等于的数,找到后填到前一个坑中
while(i<j&&arr[i]<x){
i++;
}
if(i<j){
arr[j]=arr[i];
j--;
}
arr[i] = x; //把基本数填到最后一个坑中
}
return i;
}
}
归并排序
merge and sort
将初始序列看做n个长度为1 的有序子序列,两两归并
(有bug)
package com.array.arraysort;
import java.util.Arrays;
public class MergeSort {
public static void main(String[] args) {
//int[] arr = {2,1,34,5,7,56,3,23};
int[] arr = {4,6,7,9,56,3,5,8,10,45};
// 拆分
split(arr,0,arr.length-1);
// 归并
//merge(arr,0,arr.length/2-1,arr.length-1);
System.out.println(Arrays.toString(arr));
}
private static void split(int[] arr,int start,int end) {
// 计算中间索引
int middle = (start+end)/2;
if(start<end){
split(arr,start,middle);
split(arr,middle+1,end);
merge(arr,start,middle,end);
}
}
private static void merge(int[] arr, int start, int middle, int end) {
// 定义一个临时数组
int[] temp = new int[end-start+1];
// 定义左边数组的起始索引
int i = start;
// 定义右边数组的起始索引
int j = middle+1;
// 定义临时数组的起始索引
int index = 0;
// 比较左右两个数组的元素大小,往临时数组中放
while(i<=middle&&j<=end){
if(arr[i]<=arr[j]){
temp[index]=arr[i];
i++;
}else{
temp[index] = arr[j];
j++;
}
index++;
}
// 处理剩余元素
while(i<=middle){
temp[index] = arr[i];
i++;
index++;
}
while(j<end){
temp[index] = arr[j];
j++;
index++;
}
// 将临时数组中的元素取到原数组中
for(int k = 0;k<temp.length;k++){
arr[k+start]=temp[k];
}
}
}
基数排序
分配 + 收集,又名桶排序
- 先按照各位数分配
- 将桶中的数据取出(从前往后,从上往下)
- 按照十位的数字分配
- 将桶中的数据取出
- 按照百位的数字再进行分配
- 重复(数字最高位次即可完成排序)
package com.array.arraysort;
import java.util.Arrays;
// bucket sort
public class BucketSort {
public static void main(String[] args) {
// assign and collect
int[] arr = {1,34,5,23,6,7,9,324,5346,43,214,4,324,5};
// determine sort time
// get the largest number in the arr
//int max = getMax(arr);
// bucket sort
sortArray(arr);
System.out.println(Arrays.toString(arr));
}
private static void sortArray(int[] arr) {
// define 10 buckets using 2d array
int[][] temp = new int[10][arr.length];
// define an array to count
int[] counts = new int[10];
int max = getMax(arr);
int len = String.valueOf(max).length();
// loop
for(int i = 0,n=1;i<len;i++,n*=10){
for (int j = 0; j < arr.length; j++) {
// get each number
int remainder = arr[j]/n%10;
temp[remainder][counts[remainder]++] = arr[j];
}
// get element in the buckets;
int index = 0;
for (int k = 0; k < counts.length; k++) {
if(counts[k]!=0){
for (int h = 0; h < counts[k]; h++) {
// get ele from buckets, put into original bucket
arr[index] = temp[k][h];
index++;
}
counts[k] = 0; // clear last count number
}
}
}
}
private static int getMax(int[] arr) {
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if(arr[i]>max){
max = arr[i];
}
}
return max;
}
}
堆排序
是一种选择排序
基本思想
- 将待排序序列构成一个大顶堆,此时,整个序列的最大值就是堆顶的根结点
- 将其与末尾元素进行交换,此时末尾就为最大值
- 然后将剩余 n-1 个元素重新构造成一个堆,这样就会得到n个元素的次小值
- 如此反复执行,便能得到一个有序序列
大顶堆:父结点大于等于左右子节点
小顶堆:父结点小于等于左右子节点
// big top heap; ascenfing
arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2];
// small top heap; descending
arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]
将数组看为完全二叉树 —> 转成大顶堆
从最后一个非叶子结点开始转
如果其子节点大于该节点,则交换,否则不动
保证每一个子树都满足大顶堆
根结点的元素和最后一个节点进行换位
对除了当前数的最后一个元素(即整个树的最大值)之外的树进行大顶堆的调整
循环
package com.array.arraysort;
import java.util.Arrays;
public class HeapSort {
public static void main(String[] args) {
// define an array
int[] arr = {1,34,5,23,6,7,9,324,5346,43,214,4,324,5};
// adjust to big top heap
// toMaxHeap(arr,arr.length,1);
// 定义开始调整的位置
int startIndex = (arr.length-1)/2; // 最后一个非叶子节点
// 循环开始调
for (int i = startIndex; i >= 0; i--) {
toMaxHeap(arr,arr.length,i);
}
System.out.println(Arrays.toString(arr));
// 经过上面的操作,已经把数组变成了一个大顶堆
// 把跟元素和最后一个元素进行调换
for (int i = arr.length-1;i>0;i--){
// 进行调换
int t = arr[0];
arr[0] = arr[i];
arr[i] = t;
// 换完之后,再把剩余元素换成大顶堆
toMaxHeap(arr,i,0);
}
System.out.println(Arrays.toString(arr));
}
/**
* @param arr 要排序的数组;
* @param size 调整的元素个数
* @param index 从哪里开始调整
*/
private static void toMaxHeap(int[] arr, int size, int index) {
// 获取左右子节点的索引
int leftNodeIndex = index * 2 + 1;
int rightNodeIndex = index * 2 + 2;
// 查找最大节点所对应的索引
int maxIndex = index;
if(leftNodeIndex<size && arr[leftNodeIndex] > arr[maxIndex]){
maxIndex = leftNodeIndex;
}
if(rightNodeIndex<size && arr[rightNodeIndex] > arr[maxIndex]){
maxIndex = rightNodeIndex;
}
// 调换位置
if(maxIndex != index){
int t = arr[maxIndex];
arr[maxIndex] = arr[index];
arr[index] = t;
// 调换完之后可能会影响到下面的子树,不是大顶堆
toMaxHeap(arr,size,maxIndex);
}
}
}