排序算法总结
1.冒泡排序
1)算法思路
每次从第一个数开始,比较相邻两个数的大小,如果第一个数比第二个数大,则交换,每趟之后最大的元素放在了最后的位置,重复以上步骤除了最后一个元素,直到没有任何一对数字需要比较。
2)算法实现
public class BubbleSort {
public static void bubbleSort(int[] arr){
if(arr == null || arr.length < 2)
return;
for(int end = arr.length - 1; end > 0; end--){
for(int j = 0; j < end; j++){
if(arr[j] > arr[j+1])
swap(arr,j,j+1);
}
}
}
private static void swap(int[] arr, int j, int i) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
3)算法复杂度
时间复杂度为O(N*2),空间复杂度为O(1)。
2.选择排序
1)算法思路
每一次从待排序的元素中选出最小的一个元素,存放在序列的起始位置,然后,再从剩余未排序元素中继续寻找最小元素,然后放到已排序序列的末尾。以此类推,直到全部待排序的数据元素排完。
2)算法实现
public class SelectSort {
public static void selectSort(int[] arr){
if(arr == null || arr.length < 2)
return;
for(int i = 0; i < arr.length - 1; i++){
int minIndex = i;
for(int j = i+1; j < arr.length; j++){
minIndex = arr[j] < arr[minIndex] ? j : minIndex;
}
swap(arr,i,minIndex);
}
}
private static void swap(int[] arr, int j, int i) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
3)算法复杂度
时间复杂度为O(N*2),空间复杂度为O(1)。
3.插入排序
1)算法思路
每一趟将一个待排序的元素按其大小插入到已经排好序的一组元素的适当位置上,直到所有待排序记录全部插入为止。
2)算法实现
public class InsertSort {
public static void insertSort(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);
}
}
}
private static void swap(int[] arr, int j, int i) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
3)算法复杂度
时间复杂度为O(N*2),空间复杂度为O(1)。
4.归并排序
1)算法思路
归并排序采用了分治法的思想,将两个(或两个以上)有序表合并成一个新的有序表,即先把待排序序列分为若干个子序列,每个子序列是有序的,然后再把有序子序列合并为整体有序序列。若将两个有序表合并成一个有序表,称为2-路归并。
2)算法实现
public class MergeSort {
public static void mergeSort(int[] arr){
if(arr == null || arr.length < 2)
return;
sortProcess(arr,0,arr.length - 1);
}
public static void sortProcess(int[] arr, int L, int R) {
if(L == R)
return;
int mid = L+(R-L)>>1;
sortProcess(arr,L,mid);
sortProcess(arr,mid+1,R);
merge(arr,L,mid,R);
}
public static void merge(int[] arr, int L, int mid, int R) {
int[] help = new int[R-L+1];
int i = 0;
int p1 = L;
int p2 = mid + 1;
while(p1 <= mid && p2 <= R){
help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
}
while(p1 <= mid){
help[i++] = arr[p1++];
}
while(p2 <= R){
help[i++] = arr[p2++];
}
for(i =0; i < arr.length; i++){
arr[L + i] = help[i];
}
}
}
3)算法复杂度
时间复杂度为O(N*logN),空间复杂度为O(N)。
5.堆排序
1)算法思路
将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。
2)算法实现
public class HeapSort {
public static void heapSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
for (int i = 0; i < arr.length; i++) {
heapInsert(arr, i);
}
int size = arr.length;
swap(arr, 0, --size);
while (size > 0) {
heapify(arr, 0, size);
swap(arr, 0, --size);
}
}
public static void heapInsert(int[] arr, int index) {
while (arr[index] > arr[(index - 1) / 2]) {
swap(arr, index, (index - 1) / 2);
index = (index - 1) / 2;
}
}
public static void heapify(int[] arr, int index, int size) {
int left = index * 2 + 1;
while (left < size) {
int largest = left + 1 < size && arr[left + 1] > arr[left] ? left + 1 : left;
largest = arr[largest] > arr[index] ? largest : index;
if (largest == index) {
break;
}
swap(arr, largest, index);
index = largest;
left = index * 2 + 1;
}
}
public static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
3)算法复杂度
时间复杂度O(N*logN),额外空间复杂度O(1)
6.快速排序
1)算法思路
将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。
2)算法实现
public class QuickSort {
public static void quickSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
quickSort(arr, 0, arr.length - 1);
}
public static void quickSort(int[] arr, int L, int R) {
if (L < R) {
swap(arr, L + (int) (Math.random() * (R - L + 1)), R);// 随机快排
int[] p = partition(arr, L, R);
quickSort(arr, L, p[0] - 1);
quickSort(arr, p[1] + 1, R);
}
}
private static int[] partition(int[] arr, int L, int R) {
int less = L - 1;
int more = R;
while (L < more) {
if (arr[L] < arr[R]) {
swap(arr, ++less, L++);
} else if (arr[L] > arr[R]) {
swap(arr, --more, L);
} else {
L++;
}
}
swap(arr, more, R);
return new int[] { less + 1, more };
}
private static void swap(int[] arr, int j, int i) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
3)算法复杂度
时间复杂度O(N*logN),额外空间复杂度O(logN)
7.桶排序
1)算法思路
工作的原理是将数组分到有限数量的桶子里,每个桶子再个别排序。
1.初始化装入连续区间元素的n个桶,每个桶用来装一段区间中的元素。
2.遍历待排序的数据,将其映射到对应的桶中,保证每个桶中的元素都在同一个区间范围中。
3.对每个桶进行排序,最终将所有桶中排好序的元素连起来。
2)算法实现
public class BucketSort {
public static void bucketSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
int max = Integer.MIN_VALUE;
for (int i = 0; i < arr.length; i++) {
max = Math.max(max, arr[i]);
}
int[] bucket = new int[max + 1];
for (int i = 0; i < arr.length; i++) {
bucket[arr[i]]++;
}
int i = 0;
for (int j = 0; j < bucket.length; j++) {
while (bucket[j]-- > 0) {
arr[i++] = j;
}
}
}
}
3)算法复杂度
时间复杂度O(N),额外空间复杂度O(N)
8.希尔排序
1)算法思路
希尔排序是插入排序的一种又称“缩小增量排序”,是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。
2)算法实现
public class ShellSort {
public static void shellSort(int[] arr) {
int h = 1;
// 计算最大的h值
while (h <= arr.length / 3) {
h = h * 3 + 1;
}
while (h > 0) {
for (int i = h; i < arr.length; i++) {
if (arr[i] < arr[i - h]) {
int tmp = arr[i];
int j = i - h;
while (j >= 0 && arr[j] > tmp) {
arr[j + h] = arr[j];
j -= h;
}
arr[j + h] = tmp;
}
}
System.out.println("h = "+h);
h = (h - 1) / 3;
}
}
3)算法复杂度
时间复杂度O(N^1.3),额外空间复杂度O(N)
9.基数排序
1)算法思路
将整数按位数切割成不同的数字,然后按每个位数分别比较。具体是:将所有待比较数值统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。
2)算法实现
public class RadixSort {
public static void radixSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
radixSort(arr, 0, arr.length - 1, maxbits(arr));
}
public static int maxbits(int[] arr) {
int max = Integer.MIN_VALUE;
for (int i = 0; i < arr.length; i++) {
max = Math.max(max, arr[i]);
}
int res = 0;
while (max != 0) {
res++;
max /= 10;
}
return res;
}
public static void radixSort(int[] arr, int begin, int end, int digit) {
final int radix = 10;
int i = 0, j = 0;
int[] count = new int[radix];
int[] bucket = new int[end - begin + 1];
for (int d = 1; d <= digit; d++) {
for (i = 0; i < radix; i++) {
count[i] = 0;
}
for (i = begin; i <= end; i++) {
j = getDigit(arr[i], d);
count[j]++;
}
for (i = 1; i < radix; i++) {
count[i] = count[i] + count[i - 1];
}
for (i = end; i >= begin; i--) {
j = getDigit(arr[i], d);
bucket[count[j] - 1] = arr[i];
count[j]--;
}
for (i = begin, j = 0; i <= end; i++, j++) {
arr[i] = bucket[j];
}
}
}
public static int getDigit(int x, int d) {
return ((x / ((int) Math.pow(10, d - 1))) % 10);
}
}
3)算法复杂度
时间复杂度O(N),额外空间复杂度O(N)