更正:
(1)快速排序的空间复杂度:最好/平均情况:O(logn) 最坏情况:O(n)
(2)希尔排序的时间复杂度与增量序列的选择有关。
时间复杂度:可以认为是对排序数据总的操作次数,反映当n变化时,操作次数呈现的规律。
空间复杂度:指算法在计算机内执行时所需存储空间的度量,也表现为n的函数。
算法稳定性:假设在数组中存在a[i] = a[j],若在排序之前,a[i]在a[j]的前面。排序之后,a[i]仍然在a[j]的前面。则这个算法就是稳定的。
动图演示:https://www.cnblogs.com/onepixel/articles/7674659.html
1. 冒泡排序
public class BubbleSort {
public void bubbleSort(int[] data) {
if (data == null || data.length == 0) {
return;
}
int N = data.length;
boolean didSwap = false;
for (int i = 0; i < N - 1; i++) {
for (int j = 0; j < N - 1 - i; j++) {
if (data[j] > data[j + 1]) {
swap(data, j, j + 1);
didSwap = true;
}
}
if (!didSwap) return;
}
}
private void swap(int[] data, int i, int j) {
int temp = data[i];
data[i] = data[j];
data[j] = temp;
}
public static void main(String[] args) {
BubbleSort bubble = new BubbleSort();
int[] data = {49, 38, 65, 97, 76, 13, 27, 49};
bubble.bubbleSort(data);
System.out.println(Arrays.toString(data));
}
}
2. 快速排序
快速排序(Quick Sort)使用分治法策略。它的基本思想是:选择一个基准元素,通过一趟排序将待排序的数据分成独立的两部分。其中一部分的所有数据都比另一部分的所有数据要小。然后,再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据序列变成有序的。
public class QuickSort {
public void quickSort(int[] data) {
if (data == null || data.length == 0) {
return;
}
quickSort(data, 0, data.length - 1);
}
private void quickSort(int[] data, int start, int end) {
if (start >= end ) {
return;
}
int pivotIndex = partition(data, start, end); //基准元素的位置
quickSort(data, start, pivotIndex - 1);
quickSort(data, pivotIndex + 1, end);
}
private int partition(int[] data, int start, int end) {
int i = start, j = end;
int pivotKey = data[i]; //基准元素的值
while (i < j) {
while (i < j && data[j] >= pivotKey)
j--;
if (i < j)
data[i++] = data[j];
while (i < j && data[i] <= pivotKey)
i++;
if (i < j)
data[j--] = data[i];
}
data[i] = pivotKey;
return i;
}
public static void main(String[] args) {
QuickSort quick = new QuickSort();
int[] data = {49, 38, 65, 97, 76, 13, 27, 49};
quick.quickSort(data);
System.out.println(Arrays.toString(data));
}
}
3. 直接插入排序
基本思想:把n个待排序的元素看成一个有序表和一个无序表。开始时有序表中只包含一个元素,无序表中包含n-1个元素,排序过程中每次从无序表中取出第一个元素,将它插入到有序表中的适当位置,使之成为新的有序表,重复n-1次可完成排序过程。
public class InsertSort {
public void insertSort(int[] data) {
if (data == null || data.length == 0) {
return;
}
int N = data.length;
for (int i = 1; i < N; i++) {
int insertValue = data[i];
int j = i - 1;
while (j >= 0 && insertValue < data[j]) {
data[j + 1] = data[j];
j--;
}
data[j+1] = insertValue;
}
}
public static void main(String[] args) {
InsertSort insert = new InsertSort();
int[] data = {38, 65, 97, 76, 13, 27, 49};
insert.insertSort(data);
System.out.println(Arrays.toString(data));
}
}
4. 希尔排序(缩小增量排序)
它的基本思想:对于n个待排序的数列,取一个小于n的整数increment(增量)将待排序元素分成若干组子序列,所有距离第一个元素(下标为0)为increment的倍数的记录放在同一个组中。然后,对各组中的元素进行直接插入排序。之后减小increment的值,并重复执行上述的分组和排序。最后一个增量等于1,完成排序过程。
public class ShellSort {
public void shellSort(int[] data) {
if (data == null || data.length == 0) {
return;
}
int N = data.length;
for (int increment = N / 2; increment > 0; increment /= 2) {
for (int i = increment; i < N; i++) {
int tempValue = data[i];
int j = i - increment;
while (j >= 0 && tempValue < data[j]) {
data[j + increment] = data[j];
j = j - increment;
}
data[j + increment] = tempValue;
}
}
}
public static void main(String[] args) {
ShellSort shell = new ShellSort();
int[] data = {38, 65, 97, 76, 13, 27, 49};
shell.shellSort(data);
System.out.println(Arrays.toString(data));
}
}
5. 简单选择排序
public class SelectSort {
public void selectSort(int[] data) {
if (data == null || data.length == 0) {
return;
}
int N = data.length;
for (int i = 0; i < N; i++) {
int minValue = data[i];
int minIndex = i;
for (int j = i + 1; j < N; j++) {
if (data[j] < minValue) {
minValue = data[j];
minIndex = j;
}
}
if (minIndex != i) {
data[minIndex] = data[i];
data[i] = minValue;
}
}
}
public static void main(String[] args) {
SelectSort select = new SelectSort();
int[] data = {49, 38, 65, 97, 76, 13, 27, 49};
select.selectSort(data);
System.out.println(Arrays.toString(data));
}
}
6. 堆排序
堆排序是指利用堆(完全二叉树)这种数据结构所设计的一种排序算法,比较适合于数据量非常大的场合。而快速排序与归并排序是基于递归实现的,所以在数据量非常大时会发生堆栈溢出错误。
堆分为“最大堆”和“最小堆”。最大堆通常用于进行“升序”排序,而最小堆通常用于进行“降序”排序。
基本思想:将待排序的序列构造成一个最大堆。此时,整个序列的最大值就是堆顶的根节点,将其与数组的末尾元素交换,此时末尾元素就是最大值。然后,将剩余的n-1个序列重新构造成一个堆,再与数组中倒数第二个元素交换。如此反复执行,就能得到一个有序的序列。即:
(1)初始化最大堆
(2)输出堆顶元素,调整剩余元素成为一个新的最大堆
数组实现的二叉堆的性质:
性质一:索引为i的节点的左子节点的下标为 (2*i + 1);
性质二:索引为i的节点的右子节点的下标为 (2*i + 2);
性质三:索引为i的节点的父节点的下标为 floor((i-1) / 2)。
public class HeapSort {
public void heapSort(int[] data) {
if (data == null || data.length == 0) {
return;
}
int N = data.length;
for (int i = N/2 - 1; i >= 0; i--) {
adjustSort(data, i, N-1);
}
for (int i = N-1; i > 0; i--) {
swap(data, 0, i);
adjustSort(data, 0, i-1);
}
}
private void adjustSort(int[] data, int start, int end) {
if (start >= end) {
return;
}
int index = start;
int value = data[index];
for (int i = 2 * index + 1; i <= end; i = 2 * i + 1) {
if (i < end && data[i] < data[i+1]) {
i++;
}
if (value >= data[i]) {
break;
} else {
swap(data, index, i);
index = i;
}
}
}
private void swap(int[] data, int i, int j) {
int temp = data[i];
data[i] = data[j];
data[j] = temp;
}
public static void main(String[] args) {
HeapSort heap = new HeapSort();
int[] data = {49, 38, 65, 97, 76, 13, 27, 49};
heap.heapSort(data);
System.out.println(Arrays.toString(data));
}
}
7. 归并排序
归并排序就是利用归并的思想对数列进行排序。
public class MergeSort {
public void mergeSort(int[] data) {
if (data == null || data.length == 0) {
return;
}
mergeSort(data, 0, data.length - 1);
}
private void mergeSort(int[] data, int start, int end) {
if (start >= end) {
return;
}
int mid = (start + end) / 2;
mergeSort(data, start, mid);
mergeSort(data, mid + 1, end);
merge(data, start, mid, end);
}
private void merge(int[] data, int start, int mid, int end) {
int L = end - start + 1;
int[] temp = new int[L]; //temporary area
int i = start, j = mid + 1;
int k = 0; //the index of created temporary area
while (i <= mid && j <= end) {
if (data[i] <= data[j]) {
temp[k++] = data[i++];
} else {
temp[k++] = data[j++];
}
}
while (i <= mid) {
temp[k++] = data[i++];
}
while (j <= end) {
temp[k++] = data[j++];
}
System.arraycopy(temp, 0, data, start, L);
}
public static void main(String[] args) {
MergeSort merge = new MergeSort();
int[] data = {49, 38, 65, 97, 76, 13, 27, 49};
merge.mergeSort(data);
System.out.println(Arrays.toString(data));
}
}
8. 基数排序
public class RadixSort {
public void radixSort(int[] data) {
if (data == null || data.length == 0) {
return;
}
int max = getMax(data);
for (int exp = 1; max/exp > 0; exp *= 10) {
countSort(data, exp);
}
}
private void countSort(int[] data, int exp) {
int N = data.length;
int[] output = new int[N];
int[] buckets = new int[10];
for (int i = 0; i < N; i++) {
buckets[(data[i]/exp)%10]++;
}
for (int i = 1; i < 10; i++) {
buckets[i] += buckets[i - 1];
}
for (int i = N - 1; i >= 0; i--) {
output[buckets[(data[i]/exp)%10] - 1] = data[i];
buckets[(data[i]/exp)%10]--;
}
System.arraycopy(output, 0, data, 0, N);
}
private int getMax(int[] data) {
int max = data[0];
for (int i = 1; i < data.length; i++) {
if (data[i] > max) {
max = data[i];
}
}
return max;
}
public static void main(String[] args) {
RadixSort radix = new RadixSort();
int[] data = {49, 38, 65, 97, 76, 13, 27, 49};
radix.radixSort(data);
System.out.println(Arrays.toString(data));
}
}