先上个网络图
分类如下
先从基本的开始:
// 选择排序
void selectSort(int[] arr) {
int len = arr.length;
int min;
for (int i = 0; i < len - 1; i++) {
min = i;
for (int j = i + 1; j < len; j++) {
if (arr[j] < arr[min]) {
min = j;
}
}
// 需要时才交换
if (min != i) {
swap(arr, min, i);
}
}
print(arr);
}
// 冒泡排序
void bubbleSort(int[] arr) {
int len = arr.length;
for (int i = 0; i < len - 1; i++) {// 最坏情况下n-1次循环
boolean finish = true;
for (int j = 0; j < len - i - 1; j++) {// 每次将最大的数移到右端
if (arr[j] > arr[j + 1]) {
swap(arr, j, j + 1);
finish = false;
}
}
if (finish)// 如果一次都不交换,说明已经完成,不需要循环到n-1次了
break;
}
print(arr);
}
// 插入排序
void insertSort(int[] arr) {
int len = arr.length;
int j = 0;
while (j++ < len - 1) {// 从1到n-1向前面去插
int temp = arr[j];
int k;
for (k = j - 1; k >= 0; k--) {
if (temp < arr[k])
arr[k + 1] = arr[k];
else
break;
}
arr[k + 1] = temp;// 要么break出来,要么循环完k为-1
}
print(arr);
}
下面是快速排序,附上2个版本,一个以数组右端为基准进行分组,一个以数组首中尾元素的中值进行分组,这样可以分的更均匀些。
// 快速排序
void fastSort(int[] arr) {
sort(arr, 0, arr.length - 1);
// print(arr);
}
int rightHead = 0;
private void sort(int[] arr, int i, int j) {
if (i >= j)
return;
rightHead = div(arr, i, j);
sort(arr, i, rightHead - 1);
sort(arr, rightHead + 1, j);
}
// 以最右端的元素作为标准,小于它的放左边,大于它的放右边
// 返回第二个数组首端下标
private int div(int[] arr, int i, int j) {
int l = i - 1;
int r = j;
int temp = arr[j];
while (true) {
// 下面2个while为了寻找一对需要交换的元素
/*
* while(arr[++l]<temp)//不取等号防止进行到最后继续进行,数组越界 ;
*/
while (l < j && arr[++l] <= temp)// 取等号,需限制一下
;
while (r > 0 && arr[--r] >= temp)// 可以取等号有r>0保障
;
if (l >= r)
break;
else
swap(arr, l, r);
}
swap(arr, l, j);// 最后l>=r。将右端元素交换到第二个数组首端
return l;
}
// 快速排序2
// 快速排序极不稳定,所以基准元素的选取使用首尾中三个元素的中间值
void fastSort2(int[] arr) {
sort2(arr, 0, arr.length - 1);
// print(arr);
}
private void sort2(int[] arr, int i, int j) {
if (j - i + 1 <= 3) {// 小于3个元素手动排序,也可以设置为其他数值
manualSort(arr, i, j);
} else {
rightHead = div2(arr, i, j);
sort2(arr, i, rightHead - 1);
sort2(arr, rightHead + 1, j);
}
}
private void manualSort(int[] arr, int i, int j) {
if (i >= j)
return;
for (int k = i + 1; k <= j; k++) {
int temp = arr[k];
int m = k;
while (--m >= i && temp < arr[m])
arr[m + 1] = arr[m];
arr[m + 1] = temp;
}
}
private int div2(int[] arr, int i, int j) {
int temp = innerSort(arr, i, j);
int l = i;// 第1个数已然小于等于temp
int r = j - 1;// 同理最后2个数已然大于等于temp
while (true) {
while (arr[++l] < temp)
;
while (arr[--r] > temp)
;
if (l >= r)
break;
else
swap(arr, l, r);
}
swap(arr, l, j - 1);
return l;
}
// 排序首中尾,并将中间数与倒数第二个元素交换,返回中间值
private int innerSort(int[] arr, int i, int j) {
int mid = (i + j) / 2;
if (arr[i] > arr[mid])
swap(arr, i, mid);
if (arr[i] > arr[j])
swap(arr, i, j);
if (arr[mid] > arr[j])
swap(arr, mid, j);
swap(arr, mid, j - 1);
return arr[j - 1];
}
下面是归并排序,思想是不断等分2组,然后2组元素逐个比较聚合成有序的1个数组
// 归并排序
void mergeSort(int[] arr) {
merge(arr, 0, arr.length - 1);
print(arr);
}
private void merge(int[] arr, int i, int j) {
if (i >= j)
return;
int mid = (i + j) / 2;
merge(arr, i, mid);
merge(arr, mid + 1, j);
gather(arr, i, mid + 1, j);
}
private void gather(int[] arr, int f, int m, int e) {
int n = e - f + 1;
int[] b = new int[n];
int low = f;
int mid = m - 1;
int j = 0;
while (low <= mid && m <= e) {
if (arr[low] <= arr[m])// 左边数组与右边数组进行比较
b[j++] = arr[low++];
else
b[j++] = arr[m++];
}
// 左边没排完
while (low <= mid)
b[j++] = arr[low++];
while (m <= e)
b[j++] = arr[m++];
for (int i = 0; i < n; i++)
arr[f + i] = b[i];
}
希尔排序:以一定的递减间隔进行插入排序,在开始的时候就可以将数组变得比较有序,后面排序工作量就少了。间隔的选择最好是质数序列。
// 希尔排序:插入排序的优化。每次都对间隔h的序列使用插入排序,间隔逐渐递减到1,就排好了
void shellSort(int[] arr) {
int h = 1;
while (h <= arr.length / 3)
h = 3 * h + 1;// 先获取一个合适的h,再原路递减回1(只要能递减回1就没问题,效率可能有差异,h序列最好是质数)
int i, k;
while (h > 0) {
for (i = h; i < arr.length; i++) {
int temp = arr[i];
k = i;
while (k - h >= 0 && temp < arr[k - h]) {
arr[k] = arr[k - h];
k = k - h;
}
arr[k] = temp;
}
h = (h - 1) / 3;
}
print(arr);
}
奇偶排序:不断交替地对奇数下标元素与其相邻元素比较交换,和对偶数下标元素同样作用。直到数组有序
// 奇偶排序,也算高效的排序,处理器可以同时进行奇偶的循环
void oddEvenSort(int[] arr) {
int n = arr.length;
boolean unsorted = true;
while (unsorted) {
int i = 0;
boolean b1 = evenSort(arr, i);
i = 1;
boolean b2 = evenSort(arr, i);
unsorted = b1 || b2;
}
print(arr);
}
private boolean evenSort(int[] arr, int i) {
boolean unsorted = false;
while (i < arr.length - 1) {
if (arr[i] > arr[i + 1]) {
swap(arr, i, i + 1);
unsorted = true;
}
i += 2;
}
return unsorted;
}
基数排序:
// 基数排序/桶排序:按照个位对元素排序,然后放回数组,再对十位排序放回数组。。。
// 如果元素最长为len,那么d为10^len
void tankSort(int[] arr, int d) {
int n = 1;
int k = 0;
int[][] array = new int[10][arr.length];// 10个桶,每个长度为数组长度
int[] nums = new int[10];// 每个桶元素个数
while (n < d) {
for (int num : arr) {
int digit = (num / n) % 10;
array[digit][nums[digit]++] = num;
}
// 按个位或其他位排好一次后重新放入数组
for (int i = 0; i < 10; i++) {
if (nums[i] != 0) {
for (int j = 0; j < nums[i]; j++) {
arr[k++] = array[i][j];
}
}
nums[i] = 0;// 重置为0
}
n *= 10;// 乘以10方便下次取更高位
k = 0;// 和nums一样重置
}
print(arr);
}
堆排序:将数组构成完全二叉树,再修改成堆即可
public class HeapSort {
class Node {
int data;
public Node(int data) {
this.data = data;
}
}
Node[] array;
int curSize;
int maxSize;
public HeapSort(int size) {
this.curSize = 0;
this.maxSize = size;
array = new Node[size];
}
boolean insert(int data) {
if (curSize == maxSize)
return false;
array[curSize] = new Node(data);
trickleUp(curSize++);
return true;
}
private void trickleUp(int index) {
int parent = (index - 1) / 2;
Node temp = array[index];
while (index > 0 && temp.data > array[parent].data) {
array[index] = array[parent];
index = parent;
parent = (parent - 1) / 2;
}
array[index] = temp;
}
Node remove() {
Node temp = array[0];
array[0] = array[--curSize];
trickleDown(0);
return temp;
}
private void trickleDown(int index) {
int large;
Node temp = array[index];
while (index < curSize / 2) {// 至少一个子节点
int left = 2 * index + 1;
int right = left + 1;
if (right < curSize && array[right].data > array[left].data)
large = right;
else
large = left;
if (temp.data < array[large].data) {
array[index] = array[large];
index = large;
} else
break;
}
array[index] = temp;
}
//堆排序
void heapSort(int[] arr) {
for (int i = 0; i < arr.length; i++)
insert(arr[i]);
for (int i = arr.length - 1; i >= 0; i--)
arr[i] = remove().data;
print(arr);
}
private void print(int[] arr) {
for (int i = 0; i < arr.length; i++)
System.out.print(arr[i] + " ");
}
// 堆排序,其实只需要trickleDown和remove方法
void sort(Node[] arr) {
array = arr;
curSize = maxSize = arr.length;
for (int i = 0; i < maxSize; i++)
System.out.print(array[i].data + " ");
System.out.println();
for (int i = maxSize / 2 - 1; i >= 0; i--)
trickleDown(i);//关键代码
for (int i = maxSize - 1; i >= 0; i--)
array[i] = remove();
for (int i = 0; i < maxSize; i++)
System.out.print(arr[i].data + " ");
}
public static void main(String[] args) {
int size = 100;
HeapSort hs = new HeapSort(size);
Random rand = new Random();
int[] arr = new int[size];
for (int i = 0; i < size; i++)
arr[i] = rand.nextInt(size * 5);
hs.heapSort(arr);
}
}