前言
现在计算机行业越来火爆, 因此许多人也加入这滚滚洪流. 本人作为小菜鸡一枚, 略有感悟五种小算法.因此随笔进行记录, 还会配以代码进行理解.
我觉得, talk is cheap, show me the code 才是硬道理.
Bubble Sort (冒泡排序)
Nothing is better than pseudocode.
function bubbleSort(A:list of sortable things)
let n = length of A
repeat
swapped = false
for i = 1 to n - 1 (inclusive) do
if A[i - 1] > A[i] then
swap(A[i - 1] and A[i])
swapped = true
end if
end for
until not swapped
end of function
伪代码就是如上所示. 那么写成实现代码就好简单了. C++代码如下所示:
// 首先我们写一个bubble 的过程
void bubble(int arr[], int n) {
int i;
int temp;
for (i = 0; i < n ; i++) {
if (arr[i] > arr[i + 1]) {
temp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = temp;
}
}
}
// 然后我们可以就来做bubbleSort
void bubbleSort(int arr[], int n) {
for (int i = n; i >= 1; i--) {
bubble(arr, i);
}
}
接下来我们上测试代码。(C++菜鸡, java也是类似, 复制过去跑把。。。。)
int main() {
int arr[] = {6, 2, 4, 1, 7, 3, 8, 9};
bubbleSort(arr, 8);
for (int i = 0; i < 8; i++) {
cout << arr[i] << " ";
}
return 0;
}
运行结果如下:
冒泡排序
我们可以来具体分析一下这个算法, 作为最简单的排序算法, 这个算法时间复杂度是. 这个算法可能是最好掌握的一个方法, 但是我们仔细想想, 这个方法其实速度对于大规模排序来说就很容易挂了. 因此并不是一个常用(好用)的方法.相较于别的的方法, 比如插入排序,冒泡的表现也是比较糟糕的...
SelectionSort (选择排序)
选择排序是一种简单直观的排序算法,无论什么数据进去都是 的时间复杂度。所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间了吧。
- 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
- 再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
重复第二步,直到所有元素均排序完毕。
废话不多说, 我们来看代码怎么写。我们先考虑选择过程
int findMaxPos(int arr[], int n) {
// 找出数组中最大元素的位置
int pos = 0; // 假设你是最大的
int max = arr[0];
for (int i = 0; i <= n; i++) {
if (arr[i] >= max) {
max = arr[i];
pos = i;
}
}
return pos;
}
找出元素最大的位置之后, 我们来做排序。
void selectionSort(int arr[], int n) {
while (n > 0) {
int pos = findMaxPos(arr, n);
int tmp = arr[n];
arr[n] = arr[pos];
arr[pos] = tmp;
n--;
}
}
测试代码就自行测试把。
算法分析: 时间复杂度
空间复杂度
表现也比较糟糕。。。。
MergeSort(合并排序)
这个方法是1945年由冯诺依曼这个人实现过.这个方法也是典型的分治法(Divide and Conquer). 作为典型的分治法,我们来看一下这个东西咋弄.
/*MergeSort part.*/
public void merge(int[] arr, int l, int m, int r) {
// divide to 2 parts.
int n1 = m - l + 1;
int n2 = r - m;
// then we need to allocate data.
int[] L = new int[n1];
int[] R = new int[n2];
// copy data.
for (int i = 0; i < n1; i++) {
L[i] = arr[l + i];
}
for (int j = 0; j < n2; j++) {
R[j] = arr[m + j + 1];
}
// then we need to merge.
int i = 0, j = 0;
int k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
}
k++;
}
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
}
public void mergeSort(int[] arr, int l, int r) {
if (l < r) {
int m = (r + l) / 2;
mergeSort(arr, l, m);
mergeSort(arr, m + 1, r);
merge(arr, l, m, r);
}
}
这个思路用的是递归(Recursive). 有兴趣的朋友可以思考一下迭代的怎么写.
QuickSort(快速排序)
/*Quick Sort*/
public int partition(int[] arr, int low, int high) {
// step 1. find a pivot.
// let's suppose the pivot is the last one.
int pivot = arr[high];
// i is the variable to count, which idx we need to swap later?
int i = low - 1;
for (int j = low; j < high; j++) {
if (arr[j] <= pivot) {
i++;
swap(arr, i, j);
}
}
// after this, we need to swap
swap(arr, i + 1, high);
return i + 1;
}
public void quickSort(int[] arr, int low, int high) {
if (low < high) {
int pivot = partition(arr, low, high);
quickSort(arr, low, pivot - 1);
quickSort(arr, pivot + 1, high);
}
}
插入排序
首先考虑一个场景: 排序一手扑克牌。开始我们左手为空,桌子的牌朝下。然后, 我们每次从桌子上拿走一张牌, 把他插入到左手中正确的位置。
仔细分析如上场景:
- 我们左手的牌是始终保持有序的
- 我们需要逐次查看我们有序的牌, 然后和我们新拿的牌作比较,决定插入位置
这也是为什么他的名字叫插入排序。
代码如下:
public void insertionSort(int[] arr) {
for (int j = 1; j < arr.length; j++) {
int key = arr[j];
int i = j - 1; // arr[0] 到 arr[i] 这部分是有序的, 等价上述场景的我们左手的牌
while (i >= 0 && arr[i] >= key) {
// 移动位置, 找到牌合适的位置, 插入。
arr[i + 1] = arr[i];
i = i - 1;
}
arr[i + 1] = key;
}
}
测试效果:
int[] arr = {5, 2, 4, 6, 1, 3, 7};
排序之后:
排序后
算法分析
时间复杂度: 。(当数组已经反向排序, 需要正向排序的时候)
空间复杂度: 。
网友评论