概括
- 稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面;
- 不稳定:如果a原本在b的前面,而a=b,排序之后a可能会出现在b的后面;
- 内排序:所有排序操作都在内存中完成;
- 外排序:由于数据太大,因此把数据放在磁盘中,而排序通过磁盘和内存的数据传输才能进行;
- 时间复杂度: 一个算法执行所耗费的时间。
- 空间复杂度:运行完一个程序所需内存的大小。
冒泡排序
一点一点移动,最大的放在最后
vector<int> insertionSort(vector<int> arr){
if(arr.size() == 0) return arr;
for(int i = 0; i < arr.size(); i++){
bool flag = false;
for(int j = 0; j < n - i - 1; j++){
if(arr[j] > arr[j+1]){
swap(arr[j], arr[j + 1]);
flag = true;
}
}
if(flag == false) break;
}
return arr;
}
优化:一次遍历之后没有元素交换提前终止
选择排序
每次选择最小的放在最前面
vector<int> insertionSort(vector<int> arr){
if(arr.size() == 0) return arr;
for(int i = 0; i < arr.size(); i++){
int min = arr[i];
for(int j = i + 1; j < arr.size(); j++){
if(arr[j] < min) min = arr[j];
}
swap(arr[i], min);
}
return arr;
}
插入排序
把每个向前元素放到该放的位置
vector<int> insertionSort(vector<int> arr){
if(arr.size() == 0) return arr;
for(int i = 1; i < arr.size(); i++){
int cru = arr[i];
int pre = i - 1;
while(pre >= 0 && arr[pre] > cru){
arr[pre + 1] = arr[pre]; //向后挪动
pre--;
}
arr[pre+1] = cru;//放到该放的位置,pre注定多减了一次,所以+1
}
return arr;
}
希尔排序
分组进行插入排序
vector<int> sheelSort(vector<int> arr){
if(arr.size() == 0) return arr;
int gap = arr.size() / 2;
while(gap > 0){
for(int i = gap; i < arr.size(); i++){
int cru = arr[i];
int pre = i - gap;
while(pre >= 0 && arr[pre] > cru){
arr[pre + gap] = arr[pre];
pre -= gap;
}
arr[pre + gap] = cru;
}
gap /= 2;
}
return arr;
}
归并排序
分治
一直向下分到最小,然后每一组进行排序(开辟新数组,挑选左右两区间内最小的放到新数组里,一直到两个数组都放完,再复制回去)
void merge_sort(int q[], int l, int r)
{
if (l >= r) return;//退出条件
//分治向下分
int mid = l + r >> 1;
merge_sort(q, l, mid);
merge_sort(q, mid + 1, r);
int k = 0, i = l, j = mid + 1;
while (i <= mid && j <= r)
if (q[i] <= q[j]) tmp[k ++ ] = q[i ++ ];
else tmp[k ++ ] = q[j ++ ];
}//挑选左右两个数组中最小的元素不断放入tmp
while (i <= mid) tmp[k ++ ] = q[i ++ ];
while (j <= r) tmp[k ++ ] = q[j ++ ];
//再装回原数组中
for (i = l, j = 0; i <= r; i ++, j ++ ) q[i] = tmp[j];
}
快速排序
- 判断退出条件
- 确定分界点 mid
- 指针移动+交换
- 递归
void quick_sort(int q[], int l, int r)
{
if (l >= r) return;
int i = l - 1, j = r + 1, x = q[(l + r ) / 2];
while (i < j)
{
do i ++ ; while (q[i] < x);
do j -- ; while (q[j] > x);
if (i < j) swap(q[i], q[j]);
}
quick_sort(q, l, j), quick_sort(q, j + 1, r);
}
堆排序
堆就是用数组储存的,左儿子2x, 右儿子2x+1
堆排序思想:把数组想成堆,排成堆,然后再从堆顶一个一个换
vector<int> heapSort(vector<int> arr){
if(arr.size() == 0) return arr;
buildHeap(arr);
int i = arr.size() - 1;
while(i > 0){
swap(arr[0], arr[i]);
i--;
adjustHeap(arr,0);
}
return arr;
}
void buildHeap(vector<int> arr){
//从最后一个非叶子节点开始向上构造最大堆
for(int i = (2 * arr.size() - 1); i >= 0; i--){
adjustHeap(arr, i);
}
}
//其实就是down操作
void adjustHeap(vector<int> arr, int i){
int maxIndex = i;
//如果有左子树并且大于父节点,最大指针指向左子树
if(i * 2 < arr.size() && arr[i * 2] > arr[i]) maxIndex = i * 2;
//如果有右子树并且大于父节点,最大指针指向右子树
if(i * 2 + 1 < arr.size() && arr[i * 2 + 1] > arr[i]) maxIndex = i * 2 + 1;
if(maxIndex != i){
swap(arr[maxIndex], arr[i]);
adjustHeap(arr,maxIndex);
}
}
计数排序
统计每个元素出现的个数存到新数组中,遍历储存数组进行排列
vector<int> countingSort(vector<int> arr){
if(arr.size() == 0) return arr;
//bias偏移值
int bias, min = arr[0], max = arr[0];
for(int i = 1; i < arr.size(); i++){
if(arr[i] > max) max = arr[i];
if(arr[i] < min) min = arr[i];
}
bias = 0 - min;
vector<int> bucket(max - min + 1, 0);
for(int i = 0; i < arr.size(); i++){
bucket[arr[i] + bias]++;
}
int k = 0;
for(int i = 0; i < bucket.size(); i++){
while(bucket[i] > 0){
arr[k++] = i;
bucket[i]--;
}
}
}
桶排序
计数排序的变化版
分区间作为桶,把每个元素放进桶里,每个桶排序,再放原数组;
vector<int> bucektSort(vector<int> arr){
if(arr.size() == 0) return arr;
int min = arr[0];
int max = arr[0];
for(int i = 1; i < arr.size(); i++){
if(arr[i] > max) max = arr[i];
if(arr[i] < min) min = arr[i];
}
//创建d/5+1个桶,每个桶存放5*i ~ 5*i + 5-1范围的数
int bucketNum = max - min / 5 + 1;
//初始化桶
vector<vector<int>> bucket(bucketNum, vector<int>(0,0));
//放入桶中
for(int i = 0; i < arr.size(); i++){
bucket[(arr[i] - min) / d].push_back(arr[i] - min);
}
//每个桶内排序
for(int i = 0; i < bucketNum; i++){
sort(bucket[i].begin(), bucket[i].end());
}
//存放结果
int k = 0;
for(int i = 0; i < bucketNum; i++){
for(int j = 0; j < bucket[i].size(); j++){
arr[k++] = bucket[i][j] + min;
}
}
return arr;
}
基数排序
从个位开始排,然后排十位…
vector<int> radixSort(vector<int> arr){
if(arr.size() == 0) return arr;
int max = arr[0];
for(int i = 1; i < arr.size(); i++){
if(arr[i] > max) max = arr[i];
}
int maxDigit = 0;
while(max != 0){
max /= 10;
maxDigit++;
}
int mod = 10, div = 1;
vector<vector<int>> bucket(10, vector<int>(0,0));
for(int i = 1; i <= maxDigit; i++){
int mod = pow(10, i);
int div = pow(10, i - 1);
for(int j = 0; j < arr.size(); j++){
int num = (arr[j] % pow) / 10;
bucket[num].push_back(arr[j]);
}
int k = 0;
for(int j = 0; j < 10; j++){
for(int k = 0; k < bucket[j].size(); k++){
arr[k++] = bucket[i][j];
}
bucket[j].clear();
}
}
return arr;
}
题目
- 179.最大数(从结果出发进行比较)