排序算法总结
排序算法总结
前言
所谓排序算法,即通过特定的算法因式将一组或多组数据按照既定模式进行重新排序。这种新序列遵循着一定的规则,体现出一定的规律,因此,经处理后的数据便于筛选和计算,大大提高了计算效率.
这里我就整理一下几种常用的排序算法,复杂度什么放在最后部分。
[目录]
- 冒泡排序(BubbleSort)
- 选择排序(SelctionSort)
- 插入排序(InsertionSort)
- 希尔排序(ShellSort)
- 快速排序(Quicksort)
- 归并排序(MergeSort)
- 堆排序(HeapSort)
- 基数排序(等待更新)
- 桶排序(等待更新)
- 计数排序(等待更新)
- 总结与比较
冒泡排序(BubbleSort)
思想
两个数比较大小,大的冒泡向后,小的向前,一直到运行结束。
代码
public void BubbleSort(int[] nums) {
int len = nums.length;
for (int i = 0; i < len; i++) {
for (int j = i + 1; j < len; j++) {
if (nums[i] > nums[j]) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
}
}
选择排序(SelctionSort)
思想
选择排序的思路就是找到最小的,放在数组的最前面,之后找第二小的,放在第二位,这里可以采用交换的方法,减少一点运算量。
(也可以找最大的放在最后面,思路相同)
代码
public static void SelctionSort(int[] nums) {
int len = nums.length;
for (int i = 0; i < len; i++) {
int min = nums[i];
int index = i;
for (int j = i + 1; j < len; j++) {
if (nums[j] < min) {
min = nums[j];
index = j;
}
}
int temp = nums[i];
nums[i] = nums[index];
nums[index] = temp;
}
}
插入排序(InsertionSort)
思想
与选择排序相似,对于该数字,找到应该插入的位置,确保数组前方一直保持有序,前方有序后方无序,一个一个插入。
(这里我里面循环是从下标1开始的,因为第一个无所谓有序无序)
代码
public static void InsertionSort(int[] nums) {
int len = nums.length;
for (int i = 1; i < len; i++) {
int value = nums[i];
int j = i - 1;
while (j >= 0 && nums[j] > value) {
nums[j + 1] = nums[j];
j--;
}
nums[j + 1] = value;
}
}
希尔排序(ShellSort)
思想
希尔排序难度一下子就加大了不少,相似与插入排序,但是这是一下子进行多个插入排序,等到基本有序的时候再缩小范围。
这里先设置了一个增量,为长度的一半,假设数组长度为8,那么一开始就是第1个和第5个插入排序,2-6,3-7,4-8.第一圈结束。然后长度为2,就是1-3-5-7和2-4-6-8排序,最后全部排序。
这块建议上网找图解,文字版的确不适合理解。
代码
public static void ShellSort(int[] nums) {
int len = nums.length;
int len_sort = len;
while (len_sort > 1) {
len_sort = len_sort / 2;
for (int t = 0; t < len_sort; t++) {
for (int i = t + len_sort; i < len; i = i + len_sort) {
for (int j = i; j > t; j = j - len_sort) {
if (nums[j] < nums[j - len_sort]) {
int temp = nums[j];
nums[j] = nums[j - len_sort];
nums[j - len_sort] = temp;
} else {
break;
}
}
}
}
}
}
快速排序(Quicksort)
思想
算是利用分治法,先选出一个key值,然后把小于key的放在左边,大于key的放在右边,然后左右两边都进行这种操作,一直到不能再次分割。
这个算是比较重要且常用的排序方法,记住要递归调用,代码虽然复杂但是思路还是比较清晰的。
代码
public static void Quicksort(int[] nums, int l, int r) {
if (l >= r) {
return;
}
int i = l, j = r;
int key = nums[l];
while (i < j) {
while (i < j && nums[j] >= key) {
j--;
}
if (i < j) {
nums[i] = nums[j];
i++;
}
while (i < j && nums[i] <= key) {
i++;
}
if (i < j) {
nums[j] = nums[i];
j--;
}
}
nums[i] = key;
Quicksort(nums, l, i - 1);
Quicksort(nums, i + 1, r);
}
归并排序(MergeSort)
思想
递归分治的思想,将数组分为待排序的子数组,等到子数组排序好了就合并,子数组分到最小的时候进行排序,两两合并,最后有序。
代码
public static void Merge(int[] nums, int start, int mid, int end) {
int i = start;
int j = mid + 1;
int k = 0;
int[] temp = new int[end - start + 1];
while (i <= mid && j <= end) {
if (nums[i] < nums[j]) {
temp[k] = nums[i];
i++;
k++;
} else {
temp[k] = nums[j];
j++;
k++;
}
}
while (i <= mid) {
temp[k] = nums[i];
k++;
i++;
}
while (j <= end) {
temp[k] = nums[j];
k++;
j++;
}
for (int t = 0; t < temp.length; t++) {
nums[start + t] = temp[t];
}
}
public static void MergeSort(int[] nums, int start, int end) {
if (start >= end) {
return;
}
int mid = start + (end - start) / 2;
MergeSort(nums, start, mid);
MergeSort(nums, mid + 1, end);
Merge(nums, start, mid, end);
}
堆排序(HeapSort)
思想
堆排序借助了堆的性质,假设使用最大堆,那么堆顶就是最大值,取下最大值进行堆的调整,就能得到次大值,直到堆为空,就可以得到排序的结果。
可以直接借助数据结构建立一个堆,也可以自己写一个模拟堆的运行。
代码
public static void HeapSort(int[] nums) {
int len = nums.length;
for (int i = len / 2 - 1; i >= 0; i--) {
adjustHeap(nums, i, len);
}
for (int j = len - 1; j > 0; j--) {
int temp = nums[j];
nums[j] = nums[0];
nums[0] = temp;
adjustHeap(nums, 0, j);
}
}
public static void adjustHeap(int[] nums, int i, int length) {
int temp = nums[i];
for (int k = i * 2 + 1; k < length; k = k * 2 + 1) {
if (k + 1 < length && nums[k] < nums[k + 1]) {
k++;
}
if (nums[k] > temp) {
nums[i] = nums[k];
i = k;
} else {
break;
}
}
nums[i] = temp;
}
基数排序(等待更新)
思想
代码
桶排序(等待更新)
思想
代码
计数排序(等待更新)
思想
代码
总结与比较
总结
有很多种排序方法,我这里只写了一些基础的,还有桶排序,基数排序计数排序什么的我没有写上去,以后有机会在写吧。
算法没有绝对的好坏之分,我们要做的是选择当前状况下的最合适的算法。
比较
排序方法 | 时间复杂度 | 空间复杂度 | 稳定性 | 比较类排序 |
---|---|---|---|---|
冒泡排序 | O(n2) | O(1) | 稳定 | 是 |
选择排序 | O(n2) | O(1) | 不稳定 | 是 |
插入排序 | O(n2) | O(1) | 稳定 | 是 |
希尔排序 | O(nlogn) | O(1) | 不稳定 | 是 |
快速排序 | O(nlogn) | O(n) | 不稳定 | 是 |
归并排序 | O(nlogn) | O(logn) | 稳定 | 是 |
堆排序 | O(nlogn) | O(1) | 不稳定 | 是 |
基数排序 | O(n*k) | O(n+k) | 稳定 | 否 |
桶排序 | O(n+k) | O(n+k) | 稳定 | 否 |
计数排序 | O(n+k) | O(k) | 稳定 | 否 |
其他
这里还做了一个主函数用于排序的,随机生成数组并排序,大家可以试试。
public static void main(String[] args) {
int[] array = new int[20];
for (int i = 0; i < array.length; i++) {
array[i] = (int) (Math.random() * 1000);
}
sort(array);
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + " ");
}
}