选择排序
-
排序思想:
-
在数组中找到最大值,记录下标maxindex,与数组中最后一个数进行交换 swap(a[maxindex],a[n-1]);
-
在剩下的数组元素中,重新找到最大值,并重复第一次操作 swap(a[maxindex],a[n-2]),直到数组排序完毕。
-
时间复杂度
最优最差都是要遍历数组n*n次,所以时间复杂度为O(n2)
选择排序是不稳定算法:举个栗子,5 8 5 2 9,第一遍之后,2会与5交换,那么原序列中两个5的顺序就被破坏了。所以不是稳定的排序算法。
-
代码实现
#include<iostream>
using namespace std;
void selectSort(int a[], int n) {
for (int j = n; j > 1; j--) {
int max = a[0];
int maxindex = 0;
for (int i = 1; i < j; i++) {
if (a[i] > max) {
max = a[i];
maxindex = i;
}
}
swap(a[maxindex], a[j - 1]);
}
}
void print(int a[], int n) {
for (int i = 0; i < n; i++) {
cout << a[i] << " ";
}
cout << endl;
}
int main() {
int a[] = { 9,7,5,3,2,1 };
selectSort(a, 6);
print(a, 6);
return 0;
}
冒泡排序
-
排序思想
-
从左到右,比较相邻的元素。如果第一个比第二个大,就交换他们两个,将最大的数放在数组的最后(也就是下标n-1位置)
-
对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
-
针对所有的元素重复以上的步骤,除了最后一个。
-
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
-
时间复杂度
最快:当输入的数据已经是正序时(都已经是正序了,我还要你冒泡排序有何用啊)。所以时 间复杂度是O(n);
最慢:当输入的数据是反序时(写一个 for 循环反序输出数据不就行了,干嘛要用你冒泡排序 呢,我是闲的吗)。所以时间复杂度是O(n2)
稳定;
-
代码实现
优化:当数组在整个排序遍历过程中,没有发生交换,说明排序数组已经是有序的了,此时可以直接结束排序过程。
#include <iostream>
using namespace std;
void bubbleSort(int a[], int n) {
for (int j = n; j > 0; j--) {
bool flag = true;
for (int i = 0; i < j-1; i++) {
if (a[i] > a[i + 1]) {
flag = false;
swap(a[i], a[i + 1]);
}
}
if (flag == true) {
return;
}
}
}
void print(int a[], int n) {
for (int i = 0; i < n; i++) {
cout << a[i] << " ";
}
cout << endl;
}
int main() {
int a[] = { 2,3,5,7,0,4 };
bubbleSort(a, 6);
print(a, 6);
return 0;
}
插入排序
-
排序思想
-
将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。
-
从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。)
-
时间复杂度
-
代码实现
优化算法,叫做拆半插入。
#include<iostream>
using namespace std;
void insertSort(int a[], int n) {
//j代表无序表第一个元素下标
for (int j = 1; j < n; j++) {
//i代表有序表最后一个元素下标
int i = j - 1;
while (i >= 0 && a[i+1] < a[i]) {
swap(a[i + 1], a[i]);
i--;
}
}
}
void print(int a[],int n) {
for (int i = 0; i < n; i++) {
cout << a[i] << " ";
}
cout << endl;
}
int main() {
int a[] = { 2,4,6,8,0,3 };
insertSort(a, 6);
print(a, 6);
return 0;
}
桶排序
-
排序思想
-
遍历原数组,找到最大值max,申请max+1个桶,初始值设为0,,即vector<int> bucket(max+1,0);
-
遍历原数组,找到每个数值对应的桶号,并对桶计数++,即bucket[a[i]]++;
-
遍历桶数组,看对应的桶内计数为多少,就取出多少下标值,放到原数组,即while(bucket[i]--) a[index++] = i;
-
时间复杂度
最快:当输入的数据可以均匀的分配到每一个桶中。
最慢:当输入的数据被分配到了同一个桶中。
-
代码实现
#include<iostream>
#include<string>
#include<vector>
using namespace std;
void bucket(vector<int>&vec) {
if (vec.size() == 0) {
return;
}
int max = vec[0];
for (int i = 1; i < vec.size(); i++) {
if (max < vec[i]) {
max = vec[i];
}
}
//申请max+1个桶
vector<int> bucket(max + 1, 0);
//遍历原数组,把相应的球放到对应的桶里
for (int i = 0; i < vec.size(); i++) {
bucket[vec[i]]++;
}
int index = 0;
//把桶中的球取出来,i代表数值,bucket[i]代表的是个数
for (int i = 0; i < bucket.size(); i++) {
while (bucket[i]>0) {
vec[index++] = i;
bucket[i]--;
}
}
}
void print(vector<int>& vec) {
for (int i = 0; i < vec.size(); i++) {
cout << vec[i] << " ";
}
cout << endl;
}
int main() {
vector<int> vec = { 2,4,6,1,3,5 };
bucket(vec);
print(vec);
return 0;
}
堆排序
-
排序思想
-
将待排序数组形象成一个堆结构,并将其调整为最大堆结构(左孩子2*i+1,右孩子2*i+2;最大堆结构中任何父节点的值都大于其子节点的值)
-
将堆顶元素与待排序数组最后一个元素交换,swap(a[0],a[nums-1]);
-
待排序的数据量减少一个,即nums--;将待排序数组重新调整最大堆结构,重复第二步,循环n-1次,将所有数据排序完毕
-
时间复杂度
堆排序是一种选择排序,整体主要由构建初始堆+交换堆顶元素和末尾元素并重建堆两部分组成。其中构建初始堆经推导复杂度为O(n),在交换并重建堆的过程中,需交换n-1次,而重建堆的过程中,根据完全二叉树的性质,[log2(n-1),log2(n-2)...1]逐步递减,近似为nlogn。所以堆排序时间复杂度最好和最坏情况下都是O(nlogn)级。
-
代码实现
#include<iostream>
#include<vector>
using namespace std;
void adjust(vector<int>&vec, int start, int end) {
int dad = start;
int son = 2 * dad + 1;
while (son <= end) {
if (son + 1 < end&&vec[son] < vec[son + 1]) {
son++;
}
if (vec[son] > vec[dad]) {
swap(vec[son], vec[dad]);
}
dad = son;
son = 2 * dad + 1;
}
}
void head_sort(vector<int>&vec) {
int n = vec.size();
for (int i = n / 2 - 1; i >= 0; i--) {
adjust(vec, i, n - 1);
}
for (int i = n - 1; i >= 0; i--) {
swap(vec[0], vec[i]);
adjust(vec, 0, i - 1);
}
}
int main() {
vector<int> vec = { 3,5,7,9,4,1 };
head_sort(vec);
for (int i = 0; i < vec.size(); i++) {
cout << vec[i] << " ";
}
cout << endl;
return 0;
}
快速排序
-
排序思想
-
三色旗思想:
一个数组只有0,1,2三种元素构成,请使用交换,原地排序而不是使用技术进行排序。
-
定义两个变量,i和j(下标);
i:<=i的部分都是比1小的,i的初值 == -1;
j:>=j的部分都是比1大的,j的初值 == n;
-
从index = 0开始遍历
如果a[index]==0,swap(a[index++],a[++i]);
(这里index++的原因是,index左边不可能有==2的数据了)
如果a[index]==1,index++;
如果a[index]==1,swap(a[index],a[--j]);
#include <iostream>
#include<vector>
using namespace std;
void Quick(vector<int>&vec, int L, int R) {
int i = L - 1;
int j = R + 1;
int temp = 1;
int index = 0;
while (index < j) {
if (vec[index] == temp) {
index++;
}
else if (vec[index] < temp) {
swap(vec[index++], vec[++i]);
}
else {
swap(vec[index], vec[--j]);
}
}
}
int main() {
vector<int> vec = { 2,1,1,0,0,2 };
Quick(vec,0, vec.size()-1);
for (auto it : vec) {
cout << it << " ";
}
return 0;
}
-
快排思想:
第一步三色旗思想:找一个基准值(这里选择排序数组最左边的那个值),然后将排序数组分成三部分
第一部分:数据全都小于基准值
第二部分:数据全都等于基准值
第三部分:数据全都大于基准值
第二步:
将第一部分和第三部分分别进行三色旗问题,直到 i >= j.
#include <iostream>
#include<vector>
using namespace std;
pair<int,int> Quick(vector<int>&vec, int L, int R) {
int i = L - 1;
int j = R + 1;
int temp = vec[L];
int index = L;
while (index < j) {
if (vec[index] == temp) {
index++;
}
else if (vec[index] < temp) {
swap(vec[index++], vec[++i]);
}
else {
swap(vec[index], vec[--j]);
}
}
return make_pair(i, j);
}
void Quick_sort(vector<int>&vec, int L, int R) {
if (L >= R) return;
pair<int,int> p = Quick(vec, L, R);
Quick_sort(vec, L, p.first);
Quick_sort(vec, p.second, R);
}
int main() {
vector<int> vec = { 2,4,1,9,0,6 };
Quick_sort(vec,0, vec.size()-1);
for (auto it : vec) {
cout << it << " ";
}
return 0;
}
-
时间复杂度
归并排序
-
排序思想
-
申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;
-
设定两个指针,最初位置分别为两个已经排序序列的起始位置;
-
比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;
-
重复步骤 3 直到某一指针达到序列尾;
-
将另一序列剩下的所有元素直接复制到合并序列尾。
-
时间复杂度
-
代码实现
#include <iostream>
#include<vector>
using namespace std;
void Merg(vector<int>&vec, int L, int mid, int R) {
//先申请一个辅助数组大小为:R-L+1;
vector<int> temp(R - L + 1);
int i = L, j = mid + 1, index = 0;
//利用while循环比较两个有序数组,分别为:L到mid,mid+1到R
while (i <= mid && j <= R) {
if (vec[i] < vec[j]) {
temp[index++] = vec[i++];
}
else {
temp[index++] = vec[j++];
}
}
while (i <= mid) {
temp[index++] = vec[i++];
}
while (j <= R) {
temp[index++] = vec[j++];
}
index = L;
for (int i = 0; i < (R - L + 1); i++) {
vec[index++] = temp[i];
}
}
void merg_sort(vector<int>&vec, int L, int R) {
if (L >= R) return;
int mid = (R - L) / 2 + L;
merg_sort(vec, L, mid);
merg_sort(vec, mid + 1, R);
Merg(vec, L, mid, R);
}
int main() {
vector<int>vec = { 20,90,60,70,40,30,50 };
merg_sort(vec, 0, vec.size() - 1);
for (auto it : vec) {
cout << it << " ";
}
return 0;
}