十大排序
1、冒泡排序
理论分析
冒泡排序是一种简单直观的排序算法。重复走访要排序的元素,每次两两对比,并进行交换。
实现
双层循环,其中内存循环一次比较相邻元素,逐渐将最边缘的数字移到最后一个位置。然后外层循环倒序遍历,最终完成排序
#include <iostream>
#include<variant>
#include<vector>
#include "User.h"
using namespace std;
void bubbile_sort(vector<int>& nums){
for(int j = nums.size()-1;j>=0;j--){
for(int i =1;i<nums.size();i++){
if(nums[i]<nums[i-1]) swap(nums[i],nums[i-1]);
}
}
}
int main() {
// using std::variant;
std::cout << "Hello, World!" << std::endl;
User u1("xiaoha",12);
// std::cout<<u1.get_name()<<std::endl;
vector<int> vec={1,3,2,5,7,8,5};
bubbile_sort(vec);
for(auto c:vec) cout<<c<<endl;
return 0;
}
2、选择排序
理论分析
是一种简单直观的排序算法,无论什么数据进入,都是o(n2)的时间复杂度。因为都是在内层循环中找最大值,然后交换到最后一个
实现
内层循环遍历当前所有元素,选择出最大的元素,和当前最后一个元素进行交换,然后外层循环依次缩小范围,最终完成排序
#include <iostream>
#include<variant>
#include<vector>
#include "User.h"
using namespace std;
void bubbile_sort(vector<int>& nums){
for(int j = nums.size()-1;j>=0;j--){
for(int i =1;i<nums.size();i++){
if(nums[i]<nums[i-1]) swap(nums[i],nums[i-1]);
}
}
}
void Selection_sort(vector<int>& nums){
for(int i = nums.size()-1;i>=0;i--){
int max=0;
for(int j=0;j<=i;j++){
max = max<nums[j]? nums[j]:max;
}
swap(nums[i],max);
}
}
int main() {
// using std::variant;
std::cout << "Hello, World!" << std::endl;
User u1("xiaoha",12);
// std::cout<<u1.get_name()<<std::endl;
vector<int> vec={1,3,2,5,7,8,5};
// bubbile_sort(vec);
Selection_sort(vec);
for(auto c:vec) cout<<c<<endl;
return 0;
}
3、插入排序
理论分析
工作原理主要为从前到后构建有序数列,对于未排序的数据,在已排序的序列中从后到前扫描,找到插入位置
实现
需要注意的是,插入排序比本身不是交换数据,而是制造插入的空格。随意在判断有序数据中的位置时,数据要以此后移,制造空位,然后将无序数据放进去
void Insert_sort(vector<int>& nums){
for(int i=0;i<nums.size();i++){
int pre = i-1;
int cur_val = nums[i];
while(pre>0&&cur_val<nums[pre]){
nums[pre+1] = nums[pre];
pre--;
}
nums[pre+1]=cur_val;
}
}
4、希尔排序
理论分析
希尔排序是插入排序的改进版本,为非稳定排序算法。
实现
5、归并排序
理论分析
归并排序和选择排序一样,不受输入数据的影响,时间复杂度始终为o(nlogn),但是需要使用额外空间
实现
思路主要为,通过递归将数组分为只有两个元素,然后定义左右指针,进行对比,并通过中间数组转存,最后再替代原数组。
void merge(int* vec,int len){
int s = 0;
int left=0;
int mid = len/2;
int right = mid;
int* arr = new int[len];
while(left<mid&&right<len){
if(vec[left]<vec[right]){
arr[s++]=vec[left++];
}
else{
arr[s++]=vec[right++];
}
}
while(left<mid){
arr[s++] = vec[left++];
}
while(right<len){
arr[s++] = vec[right++];
}
for(int i=0;i<len;i++){
vec[i]= arr[i];
}
delete []arr;
}
void merge_sort(int* vec,int len){
if(len<2) return ;
merge_sort(vec,len/2);
merge_sort(vec+len/2,len-len/2);
merge(vec,len);
}
int main() {
int arr[] = {1,3,2,5,7,8,2};
int a = sizeof(arr);
int b = sizeof(arr[0]);
int n = sizeof(arr)/sizeof(arr[0]);
merge_sort(arr,n);
for(int i=0;i<n;i++){
cout<<arr[i]<<endl;
}
return 0;
}
需要注意的是,求int数组大小需要使用sizeof(arr)/sizeof(arr[0);
6、快速排序
理论分析
该算法输入的是数组,左节点和右节点。
总体而言是一种分而治之的思想,通过保存一个基准,然后在首尾指针依次对比基准数据,使得左边数据都比基准小,右边数据都比基准大,然后再left=right处插入基准,并将左右不分送入递归
实现
int partion(int vec[],int left,int right){
int index = vec[left];
while(left<right){
while(left<right&&vec[right]>=index) right--;
vec[left]=vec[right];
while(left<right&&vec[left]<=index) left++;
vec[right]=vec[left];
}
vec[left]=index;
return left;
}
void quick_sort(int vec[],int left,int right){
if(left<right){
int mid = partion(vec,left,right);
quick_sort(vec,left,mid-1);
quick_sort(vec,mid+1,right);
}
}
7、堆排序
理论分析
堆的本质是完全二叉树,即根节点的数值一定比叶子结点大,但不保证层序遍历有序。
且当有n个二叉树结点时,n/2为最大的非叶子结点序号
每次交换最大节点之后,递归的判断换下去的字数是否为堆
实现
在选择最大值时,每次将最大值放到数组最后,然后通过heapify函数调整交换点一下的顺序,然后缩小边界,所以直接用heapify(vec,0,i)
void heapify(int vec[],int i,int len){
int left = i*2+1;
int right = i*2+2;
int max = i;
if(left<len&&vec[left]>vec[max]){
max = left;
}
if(right<len&&vec[right]>vec[max]){
max = right;
}
if(max!=i){
swap(vec[i],vec[max]);
heapify(vec, max, len);
}
}
void heap_sort(int vec[],int len){
for(int i=len/2-1;i>=0;i--){
heapify(vec,i,len);
}
for(int j=len-1;j>0;j--){
swap(vec[0],vec[j]);
heapify(vec,0,j);
}
}