1 冒泡排序
1.1 原理
假设有未排序数列array, 元素个数为n, 那么开始遍历array, 将每一个元素a和其下一个元素b进行比较, 如果a>b, 那么交换两个元素, 这样遍历一遍之后, 可以保证数列最后一个元素是最大的, 但是最后一个元素的前n-1个元素的顺序不确定, 这样把前n-1个元素当作一个新序列, 进行上述遍历并交换, 使得第n -1个元素为第二大的元素, 这样遍历n遍之后可以使得数列有序.
1.2 代码实现
class Solution {
public:
vector<int> sortArray(vector<int>& nums) {
int n = nums.size() - 1;
while (n) {
for (int i = 0; i < n; i ++) {
if (nums[i] > nums[i + 1])
swap(nums[i], nums[i + 1]);
}
n --;
}
return nums;
}
};
1.3 性能及内存
时间复杂度, 最坏时间复杂度
, 最好时间复杂度
, 空间复杂度
, 稳定, 性能测试如图.
2 选择排序
2.1 原理
选择排序即为把整个序列分为已排序序列和未排序序列, 让序列号从0开始, 一直到序列末尾, 序列号(包括自身)之前代表着已排序序列, 序列号之后代表未排序序列, 从未排序序列中找到最小元素, 与当前序列号元素进行交换, 这样遍历到结尾, 整个序列即为有序序列.
2.2 代码实现
vector<int> sortArray(vector<int>& nums) {
int n = nums.size();
for (int i = 0; i < n; i ++) {
int min_index = i;
for (int j = i + 1; j < n; j ++) {
if (nums[j] < nums[min_index]) {
min_index = j;
}
}
swap(nums[i], nums[min_index]);
}
return nums;
}
2.3 性能及内存
时间复杂度, 最坏时间复杂度
, 最好时间复杂度
, 空间复杂度
, 不稳定, 性能测试如图:
3 插入排序
3.1 原理
在待排序序列中, 从左到右进行遍历, 每遍历一个元素, 把其向前插入到合适的位置, 这样保证每遍历一个元素时, 其前面的元素都是有序的. 至于插入到合适位置的具体方法, 就是每一次都和前面的元素比较, 如果大于前面的元素, 就和其交换.
3.2 代码实现
vector<int> sortArray(vector<int>& nums) {
int n = nums.size();
for (int i = 1; i < n; i ++) {
for (int ii = i; ii > 0 && nums[ii] < nums[ii - 1]; ii --) {
swap(nums[ii], nums[ii - 1]);
}
}
return nums;
}
3.3 性能及内存
时间复杂度, 最坏时间复杂度
, 最好时间复杂度
, 空间复杂度
, 不稳定, 性能测试如图:
4 希尔排序
5 归并排序
5.1 原理
把一个无序列表分为两个列表, 然后按照依次取出最小元素的方法合并成一个新的有序表(至于两个子表怎么排序, 可以用递归的方法).
5.2 代码实现
我写的比较笨:
void vectorMergeSort(vector<int> &unorderedVec, vector<int> &orderedVec) {
if (unorderedVec.size() < 2) {
orderedVec = unorderedVec;
return;
}
vector<int> firstHalf(unorderedVec.begin(), unorderedVec.begin() + unorderedVec.size() / 2);
vector<int> secondHalf(unorderedVec.begin() + unorderedVec.size() / 2, unorderedVec.end());
vector<int> orderedFirstHalf;
vector<int> orderedSecondHalf;
vectorMergeSort(firstHalf, orderedFirstHalf);
vectorMergeSort(secondHalf, orderedSecondHalf);
auto orderedFirstHalfIter = orderedFirstHalf.begin();
auto orderedSecondHalfIter = orderedSecondHalf.begin();
while (orderedFirstHalfIter != orderedFirstHalf.end() &&
orderedSecondHalfIter != orderedSecondHalf.end()) {
if (*orderedFirstHalfIter < *orderedSecondHalfIter) {
orderedVec.push_back(*orderedFirstHalfIter);
orderedFirstHalfIter ++;
} else {
orderedVec.push_back(*orderedSecondHalfIter);
orderedSecondHalfIter ++;
}
}
if (orderedFirstHalfIter != orderedFirstHalf.end())
orderedVec.insert(orderedVec.end(), orderedFirstHalfIter, orderedFirstHalf.end());
if (orderedSecondHalfIter != orderedSecondHalf.end())
orderedVec.insert(orderedVec.end(), orderedSecondHalfIter, orderedSecondHalf.end());
}
void mergeSort(int* array, int array_size){
vector<int> arrayVec;
for_each(array, array + array_size, [&](auto element){arrayVec.push_back(element);});
vector<int> resVector;
vectorMergeSort(arrayVec, resVector);
int arrayIndex = 0;
for_each(resVector.begin(),resVector.end(), [&](auto element){array[arrayIndex ++] = element;});
}
5.3 性能及内存
时间复杂度, 最坏时间复杂度
, 最好时间复杂度
, 空间复杂度
, 稳定, 性能测试如图:
6 快速排序
7 堆排序
8 计数排序
8.1 原理
计数排序就是用一个新的数组, 数组的索引就是每个元素的值, 存的值是每个元素在原数组出现了几次, 最后再通过遍历这个频率表, 再把原数组存回去.
8.2 代码
9 桶排序
10 基数排序
10.1 原理
基数排序只能对整数进行排序, 其原理是首先把数组的每个元素按照每一位从小到大进行排序, 直到遍历到最后一位. 这样对比桶排序的好处就是, 其用到的额外空间更小.
10.2 代码
void sortPosArray(vector<int>& nums) {
if (nums.empty())
return;
//首先遍历找到最大的数
int Max = nums[0];
for (int num: nums) {
Max = max(Max, num);
}
int util = 1;
while (Max >= util) {
//把nums的每个数按照当前的取位值放进buckets里面
//取位运算: (num / util) % 10
vector<vector<int>> buckets(10, vector<int>());
for (int num: nums) {
buckets[(num / util) % 10].push_back(num);
}
//nums清了
nums.clear();
//把buckets里面的数放回nums里面
for (auto bucket: buckets) {
for (int num: bucket) {
nums.push_back(num);
}
}
util *= 10;
}
}
vector<int> sortArray(vector<int>& nums) {
vector<int> pos_num;
vector<int> neg_num;
for(int num: nums) {
if (num < 0) {
neg_num.push_back(-num);
} else {
pos_num.push_back(num);
}
}
sortPosArray(pos_num);
sortPosArray(neg_num);
int neg_n = neg_num.size();
vector<int> new_neg;
for (int i = neg_n - 1; i >= 0; i --) {
new_neg.push_back(-neg_num[i]);
}
new_neg.insert(new_neg.end(), pos_num.begin(), pos_num.end());
return new_neg;
}