static void insertion(int[] a){
for (int i = 1; i < a.length; i++) {
for (int j = i; j > 0; j--) {
if (a[j] < a[j-1]) {
swap(a, j, j-1);
}
}
}
}
static void quick(int[] a, int left, int right){
if (right<=left) {
return;
}
int i=left,j=right;
int key = a[left];//默认第一个为轴就行
while(i=key){
j--;
}
//从左到右找大于key的值
while(i
/**
* 通过递归实现一个数组分成两半基本有序
*/
static void MergeSort(int a[],int left, int right){
if (left==right) {
return;
}
//分成两半
int mid = left + (right-left)/2;
//左边排序
MergeSort(a,left,mid);
//右边排序
MergeSort(a,mid+1,right);
//合并数组
merge(a,left,mid+1,right);
}
/**
* 将两个有序的数组合并
*/
static void merge(int a[], int leftPtr, int rightPtr, int rightBound){
int mid = rightPtr - 1;
int i = leftPtr;
int j = rightPtr;
int k = 0;
int[] temp = new int[rightBound - leftPtr + 1];
while ( i <= mid && j <= rightBound ) {
if (a[i] <= a[j]) {
temp[k++] = a[i++];
}else{
temp[k++] = a[j++];
}
}
while (i <= mid) {
temp[k++] = a[i++];
}
while (j <= rightBound) {
temp[k++] = a[j++];
}
for (int l = 0; l < temp.length; l++) {
a[ l + leftPtr] = temp[l];
}
}
堆排序(Heap)
希尔排序( Shell )
优化的插入排序,希尔排序的发明使得我们突破了慢速排序时代,它的时间复杂度是O( n^1.3 ) ,不稳定。
思路:
希尔排序基于插入排序,它以一定的间隔(gap),并且是递减的,对数组进行插入排序,相较于插入排序,其移动次数更少,移动距离更短。
//二分
static void shell(int[] a){
for (int gap = a.length/2; gap > 0; gap/=2) {
for (int i = gap; i < a.length; i++) {
for (int j = i; j > gap-1; j-=gap) {
if (a[j] < a[j-gap]) {
swap(a, j, j-gap);
}
}
}
}
}
//Knuth序列
static void shell(int[] a){
//Knuth序列效率要比二分高
int h = 1;
while (h <= a.length/3) {
h = 3*h + 1;
}
for (int gap = h; gap > 0; gap=(gap+1)/3) {
for (int i = gap; i < a.length; i++) {
for (int j = i; j > gap-1; j-=gap) {
if (a[j] < a[j-gap]) {
swap(a, j, j-gap);
}
}
}
}
}
桶排序( Bucket )
计数排序( Counting )
桶思想的一种,非比较排序,适用于量大但范围小;它的时间复杂度是 O( n + k ) ,稳定。
比如:某大型企业数万名员工年龄排序?如何快速得知高考名次?
思路:
遍历数组的值 x , 在 count [ x ] ++ ,再将count按出现的次数复制到原数组;
//version 1.0
static void counting(int[] a){
int[] result = new int[a.length];
int[] count = new int[61];
for (int i = 0; i < a.length; i++) {
count[ a[i] ]++;
}
int j=0;
for (int i = 0; i < count.length; i++) {
while (count[i]-- > 0) {
result[j++] = i;
}
}
for (int i = 0; i < result.length; i++) {
a[i] = result[i];
}
}
到目前为止,计数排序version 1.0 有两大问题:其一,如果我们只要求排100~150,那么0到100的空间就会浪费;其二,算法不稳定。
对于空间的浪费,我们可以找出数组的最大和最小值;
对于算法的稳定性,解决的方法是累加数组count;
static void counting(int[] a){
int max = a[0];
int min = a[0];
for (int i = 0; i < a.length; i++) {
if (a[i] > max) {
max = a[i];
}
if (a[i] < min) {
min = a[i];
}
}
int n = a.length;
//这里k的大小是要排序的数组中,元素大小的极值差+1
int k = max - min +1;
int[] result = new int[n];
int[] count = new int[k];
for (int i = 0; i < n; i++) {
//优化过的地方,减小了数组c的大小
count[ a[i]-min ]++;
}
for (int i = 1; i < count.length; i++) {
count[i] += count[i-1];
}
int j=0;
for (int i = a.length-1; i >= 0; i--) {
result[--count[a[i]-min] ] = a[i];
}
for (int i = 0; i < result.length; i++) {
a[i] = result[i];
}
}
static void radix(int[] a){
//找到数组a的最大值
int max = a[0];
for (int i = 0; i < a.length; i++) {
if (a[i] > max) {
max = a[i];
}
}
int[] result = new int[a.length];
//按位数从低到高对数组进行排序
for (int exp = 1; max/exp > 0; exp *= 10) {
int[] count = new int[10];
//这里的思想其实跟计数排序是一样的
for (int i = 0; i < a.length; i++) {
count[(a[i]/exp)%10]++;
}
//累加数组count
for (int i = 1; i < count.length; i++) {
count[i] += count[i-1];
}
for (int i = a.length-1; i >= 0 ; i--) {
result[--count[(a[i]/exp)%10]] = a[i];
}
for (int i = 0; i < result.length; i++) {
a[i] = result[i];
}
}
}
学习资料来自马士兵的算法课程