冒泡排序
冒泡排序是最最基础的一个排序方法
重复走访相邻的元素,一次比较两个,如果顺序不符合要求就返过来
算法复杂度O(N^2)
vector<int> bubbleSort(vector<int> nums) {
for (int i = 0; i < nums.size(); i++) {
for (int j = 0; j < nums.size() - 1 -i; j++) {
if (nums[j] > nums[j + 1]) {
int temp = nums[j];
nums[j] = nums[j+1];
nums[j + 1] = temp;
}
}
}
return nums;
}
基本思想:
在一个序列中,从前往后两两数之间依次进行比较,让较大的数向后移动 ,较小的数字向上移动
如果其与我们想要的方向相反 就将两个数字进行交换
优缺点:
优点:稳定
缺点:慢,每次只能移动两个相邻的数据
选择排序
选择排序也是两层循环
自我感觉和冒泡排序有些许相似的地方
选择排序是从开始的位置
依次找当前位置之后所有元素的最小值
然后和当前位置的元素交换
vector<int> selection_sort(vector<int>nums) {
for (int i = 0; i < nums.size() - 1; i++) {
int mins = i;//i之后最小的索引
for (int j = i + 1; j < nums.size(); j++) {
if (nums[mins] > nums[j]) {
mins = j;//更换索引
}
}
swap(nums[i], nums[mins]);
}
return nums;
}
基本思想
每次遍历当前元素之后所有的元素 选出最小值 与当前元素进行交换
直至元素遍历完毕
插入排序
插入排序是遍历一次数组
从索引为1开始
每当遍历一个数字的时候,就把这个数字按照顺序插入到前面已经排序的数组中
vector<int> insert_sort(vector<int> nums) {
for (int i = 1; i < nums.size(); i++) {
int key = nums[i];
int j = i - 1;
while (j >= 0 && key < nums[j]) {
nums[j + 1] = nums[j];//向后移一位
j--;
}
nums[j+1] = key;
}
return nums;
}
基本思想:
将一个记录插入到已经排序完好的有序表中,从而得到一个新的有序表
优缺点:
优点:稳定,快
缺点:比较次数不一定,比较次数越少,插入点之后的元素越多
快速排序
快排用到了分治的思想
我们声明两个指针分别指向数组首尾
然后我们声明一个临时变量 遍历数组
将临时变量放于合适的位置
使得该变量的左右 左边都是小于该数 右边都大于该数
然后递归求解
int Paritition1(vector<int> & A, int low, int high) {
int pivot = A[low];
while (low < high) {
while (low < high && A[high] >= pivot) {
--high;
}
A[low] = A[high];
while (low < high && A[low] <= pivot) {
++low;
}
A[high] = A[low];
}
A[low] = pivot;
return low;
}
void QuickSort(vector<int> & A, int low, int high) //快排母函数
{
if (low < high) {
int pivot = Paritition1(A, low, high);
QuickSort(A, low, pivot - 1);
QuickSort(A, pivot + 1, high);
}
}
主要思想:
选择一个基准元素(升序排序),比基准元素小的放于基准元素之前,相反放于基准元素之后
然后在将小于基准值的元素子数列和大于基准值的子序列 分别按照原来的方法排序
优缺点:
优点:顾名思义 非常快,移动数据较少
缺点:不稳定
在数据越乱的时候 效率越高,如果其有序的时候,会近似冒泡排序
效率:
如果每次选到的元素都是中间位置的元素(恰好将数组分为大小相等的两块)
时间复杂度为O( nlogn ) 空间复杂度为O( logn )
如果每次都是选到最大、最小的情况下 效率为O(n^2) 近似于冒泡排序空间复杂度为O(n)
归并排序
归并排序同快速排序一样,都是分治思想的代表
我们把原问题分解成为多个子问题,然后对子问题求解 最后构造出原问题的解
void merge(vector<int>& nums, int left, int mid, int right) {
int i = left;
int j = mid + 1;
int index = 0;
vector<int> ans(right - left + 1);
while (i <= mid && j <= right) {
ans[index++] = nums[i] < nums[j] ? nums[i++] : nums[j++];
}
while (i <= mid) ans[index++] = nums[i++];
while (j <= right) ans[index++] = nums[j++];
for (int i = 0; i < index; i++) {
nums[left + i] = ans[i];
}
}
void merge_sort(vector<int>& nums, int left, int right) {
if (left >= right)return;
int mid = left + (right - left) / 2;
merge_sort(nums, left, mid);
merge_sort(nums,mid + 1, right);
merge(nums, left, mid, right);
}
主要思想:
将一个完整的数组 分成一般 一次递归下去 直至成为包含两个或者一个的小数组
将其按想要的顺序两两交换
然后在将其组合起来
顺序查找
int search(vector<int>& nums, int target) {
for (int i = 0; i < nums.size(); i++) {
if (nums[i] == target) {
return i;
}
}
return -1;
}
二分查找
二分查找的思想和分治法差不太多
元素必须是有序的,如果是无序的则要先进行排序操作。
最坏情况下,关键词比较次数为log2(n+1),且期望时间复杂度为O(log2n);
非递归
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
int mid = left + (right - left) / 2;
while (left < right) {
mid = left + (right - left) / 2;
if (nums[mid] < target) {
left = mid + 1;
}
else if (nums[mid] > target) {
right = mid - 1;
}
else {
return mid;
}
}
return -1;
}
递归
int search(vector<int>& nums, int target,int left,int right) {
int mid = (left + right) / 2;
if (target == nums[mid]) {
return mid;
}
else if(target<nums[mid]){
return search(nums, target, left, mid-1);
}
else {
return search(nums, target, mid + 1, right);
}
}
其他解法我也会陆续更新的
希望我所写的对大家有所帮助