一、十大排序
1、比较排序
1-1 初级排序( O ( n 2 ) O(n^2) O(n2))
1、冒泡: 嵌套循环,每次查看相邻元素,如果逆序,则交换。
public void bubbleSort(int[] array) {
int len = array.length;
for (int i=len-1; i>=0; i--) {
int flag = 0;
for (int j=0; j<i; i++) {
if (array[i]>array[j]) {
int temp = array[i]; array[i] = array[j]; array[j] = temp;
flag = 1;
}
}
if (flag == 0) break;
}
}
2、插入: 从前到后逐步构建有序序列;对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
public insertSort(int[] arr) {
int len = arr.length;
for (int p=1; p<len; p++) {
int temp = arr[p];
for (int i=p; i>0 && A[i-1]>temp; i--) {
arr[i] = arr[i-1];
}
a[i] = temp;
}
}
3、希尔
public static int[] shellSort(int[] arr)
{
int len = arr.length;
for (int gap=Math.floor(len/2); gap>0; gap = Math.floor(gap / 2)) {
// 注意:这里和动图演示的不一样,动图是分组执行,实际操作是多个分组交替执行
for (int pos=gap; pos<len; pos++ ) {
/* 插入排序*/
int temp = arr[pos];
for (int i=pos; i>=gap && arr[i-gap]>temp; i-=gap ) {
arr[i] = arr[i-gap];
}
arr[i] = temp;
}
}
}
// 也可自定义增量序列解决,这里只列出一小部分增量
// int Sedgewick[] = {929, 505, 209, 109, 41, 19, 5, 1, 0};
// for ( Si=0; Sedgewick[Si]>=N; Si++ );
// for ( D=Sedgewick[Si]; D>0; D=Sedgewick[++Si] )
4、选择: 每次找最小值,然后放到待排序数组的起始位置。
public static int[] selectionSort(int[] arr) {
int len = arr.length;
for(int p = 0; p < len - 1; p++) {
int minIndex = p;
for(int i = p+1; i < len; i++) {
if(arr[i] < arr[minIndex]) {
// 寻找最小的数
minIndex = i; // 将最小数的索引保存
}
}
int temp = arr[p]; arr[p] = arr[minIndex]; arr[minIndex] = temp;
}
return arr;
}
1-2 高级排序( O ( n l o g n ) O(nlogn) O(nlogn))
5、快排
public static void quickSort(int[] array, int begin, int end) {
if (end <= begin) return;
int pivot = partition(array, begin, end);
quickSort(array, begin, pivot - 1);
quickSort(array, pivot + 1, end);
}
static int partition(int[] a, int begin, int end) {
// pivot: 标杆位置,counter: 小于pivot的元素的个数
int pivot = end, counter = begin;
for (int i = begin; i < end; i++) {
if (a[i] < a[pivot]) {
int temp = a[counter]; a[counter] = a[i]; a[i] = temp;
counter++;
}
}
int temp = a[pivot]; a[pivot] = a[counter]; a[counter] = temp;
return counter;
}
6、归并
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);
}
public 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)
}
归并 VS 快排: 具有相似性,但步骤顺序相反。
归并:先排序左右子数组,然后合并两个有序子数组。
快排:先调配出左右子数组,然后对于左右子数组进行排序。
7、堆排序:插入 O ( l o g n ) O(logn) O(logn),取最大/小值 O ( 1 ) O(1) O(1)
S1:数组元素依次建立小顶堆;
S2:依次取堆顶元素,并删除。
版本1–PriorityQueue():
void heapSort(int[] arr) {
int len = arr.length;
PriorityQueue<Integer> q = new PriorityQueue<>();
for (int i=0; i<len; i++) {
q.add(a[i]);
}
for (int i=0; i<len; i++) {
a[i] = q.pop();
}
}
版本2–手动实现:
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 = leftChild;
}
if (right<length && array[right]>array[largest]) {
largest = right;
}
if (largest != i) {
int temp = array; 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 = temp;
heapify(array, i, 0);
}
}
2、非比较排序–特殊排序
8、计数排序
public static int[] countSort(int[] arr, int maxValue) {
int sortedIndex = 0;
int[] bucket = new int[maxValue+1],
for(int i = 0; i < arr.length; i++) {
bucket[arr[i]]++;
}
for(int j = 0; j < maxValue+1; j++) {
while(bucket[j] > 0) {
arr[sortedIndex++] = j;
bucket[j]--;
}
}
return arr;
}
9、桶排序
function bucketSort(arr, bucketSize) {
if (arr.length === 0) {
return arr;
}
var i;
var minValue = arr[0];
var maxValue = arr[0];
for (i = 1; i < arr.length; i++) {
if (arr[i] < minValue) {
minValue = arr[i]; // 输入数据的最小值
} else if (arr[i] > maxValue) {
maxValue = arr[i]; // 输入数据的最大值
}
}
// 桶的初始化
var DEFAULT_BUCKET_SIZE = 5; // 设置桶的默认数量为5
bucketSize = bucketSize || DEFAULT_BUCKET_SIZE;
var bucketCount = Math.floor((maxValue - minValue) / bucketSize) + 1;
var buckets = new Array(bucketCount);
for (i = 0; i < buckets.length; i++) {
buckets[i] = [];
}
// 利用映射函数将数据分配到各个桶中
for (i = 0; i < arr.length; i++) {
buckets[Math.floor((arr[i] - minValue) / bucketSize)].push(arr[i]);
}
arr.length = 0;
for (i = 0; i < buckets.length; i++) {
insertionSort(buckets[i]); // 对每个桶进行排序,这里使用了插入排序
for (var j = 0; j < buckets[i].length; j++) {
arr.push(buckets[i][j]);
}
}
return arr;
}
10、基数排序
var counter = [];
function radixSort(arr, maxDigit) {
var mod = 10;
var dev = 1;
for(var i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) {
for(var j = 0; j < arr.length; j++) {
var bucket = parseInt((arr[j] % mod) / dev);
if(counter[bucket]==null) {
counter[bucket] = [];
}
counter[bucket].push(arr[j]);
}
var pos = 0;
for(var j = 0; j < counter.length; j++) {
var value = null;
if(counter[j]!=null) {
while((value = counter[j].shift()) != null) {
arr[pos++] = value;
}
}
}
}
return arr;
}
二、参考
1、快速排序代码示例
2、十大经典排序算法(动图演示)
3、八个排序的原理、Java 实现以及算法分析
4、Java学习笔记–PriorityQueue(优先队列)(堆)