首先我先抛一个老哥的博客,我是看着他的博客来学习理解
地址:https://www.cnblogs.com/onepixel/p/7674659.html
首先说一下排序算法分为2类:一类是比较类排序算法,另一类是非比较类排序,这里主要讲常用的比较类排序算法
包括插入排序,选择排序,冒泡排序,希尔排序,快速排序,归并排序,堆排序
先讲一下各个算法的复杂度
时间复杂度方面,快速排序,归并排序,堆排序的是最好的,一般比较常用。
1.插入排序(时间复杂度o(n2))
它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
通俗的讲就是从第二个开始依次跟之前的元素做比较,如果比前一个元素小则交换位置,直到成为第一个元素或者前一个元素小于该元素。
附一下c++代码:
#include <iostream>
using namespace std;
int main() {
int num;
cin>>num;
int nums[num];
for(int i=0;i<num;i++)
cin>>nums[i];
for(int i=1;i<num;i++){
int j=i;
while(j>=1){
if(nums[j]<nums[j-1]){
int temp=nums[j-1];
nums[j-1]=nums[j];
nums[j]=temp;
}
j--;
}
}
for(int i=0;i<num;i++){
cout << nums[i] <<" ";
}
return 0;
}
2. 选择排序(时间复杂度o(n2))
它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
通俗讲就是在所有元素中找到最小(大)的与下标为0的元素交换,然后再在剩下的所有元素中重复上述操作即可。
附一下c++代码:
#include <iostream>
using namespace std;
int main() {
int num;
cin>>num;
int nums[num];
for(int i=0;i<num;i++)
cin>>nums[i];
for(int i=0;i<num;i++){
for(int j=i+1;j<num;j++){
if(nums[j]<nums[i]){
int temp=nums[i];
nums[i]=nums[j];
nums[j]=temp;
}
}
}
for(int i=0;i<num;i++){
cout << nums[i] <<" ";
}
return 0;
}
3. 冒泡排序(时间复杂度o(n2))
它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。
每次都是从下标为0开始到最后一个元素,第一次会把最大(小)的元素放到最后一个位置,依次类推即可。
附上c++ 代码:
#include <iostream>
using namespace std;
int main() {
int num;
cin>>num;
int nums[num];
for(int i=0;i<num;i++)
cin>>nums[i];
for(int i=0;i<num;i++){
for(int j=0;j<num-1-i;j++){
if(nums[j]>nums[j+1]){
int temp=nums[j+1];
nums[j+1]=nums[j];
nums[j]=temp;
}
}
}
for(int i=0;i<num;i++){
cout << nums[i] <<" ";
}
return 0;
}
4.希尔排序(时间复杂度o(n2))
- 选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;
- 按增量序列个数k,对序列进行k 趟排序;
- 每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
附一下c++代码:
#include <iostream>
#include <queue>
using namespace std;
void shellSort(int arr[],int n);
int main() {
int num;
cin>>num;
int nums[num];
for(int i=0;i<num;i++)
cin>>nums[i];
//希尔排序
shellSort(nums,num);
for(int i=0;i<num;i++){
cout << nums[i] <<" ";
}
return 0;
}
void shellSort(int arr[],int n) {
for (int gap = n/ 2; gap > 0; gap = gap / 2) {
// 注意:这里和动图演示的不一样,动图是分组执行,实际操作是多个分组交替执行
for (int i = gap; i < n; i++) {
int j = i;
int current = arr[i];
while (j - gap >= 0 && current < arr[j - gap]) {
arr[j] = arr[j - gap];
j = j - gap;
}
arr[j] = current;
}
}
}
5.快速排序(时间复杂度o(nlogn))
快速排序的基本思想:选择其中的一个元素(一般选择第一个元素或者最后一个)将通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。
附上c++代码
#include <iostream>
using namespace std;
void quicksort(int[],int begin,int end);
int partition(int[],int begin,int end);
int main() {
int num;
cin>>num;
int nums[num];
for(int i=0;i<num;i++)
cin>>nums[i];
//快速排序调用
quicksort(nums,0,num-1);
for(int i=0;i<num;i++){
cout << nums[i] <<" ";
}
return 0;
}
//快速排序
void quicksort(int arr[],int begin,int end){
if(end<=begin) return;
int povit=partition(arr,begin,end);
quicksort(arr,begin+1,end);
quicksort(arr,begin,end-1);
}
//找关键元素
int partition(int arr[],int begin,int end){
//pivot: 标杆 标杆位置, counter: 小于pivot的元素的个数
int pivot=end;
int counter=begin;
for(int i=begin;i<end;i++){
if(arr[i]<arr[pivot]){
int temp=arr[counter];
arr[counter]=arr[i];
arr[i]=temp;
counter++;
}
}
int temp=arr[pivot];
arr[pivot]=arr[counter];
arr[counter]=temp;
return counter;
}
6.归并排序(时间复杂度o(nlogn))
归并排序的思想是将待排序所有元素一分为二,然后两部分内部继续归并排序,直到分成的待排序元素个数小于等于2再进行归并 处理,两个 排序好的元素列表再进行合并,最后得到排序结果。
附一下c++代码
#include <iostream>
using namespace std;
void mergesort(int[],int left,int right);
void merge(int[],int left,int mid,int right);
int main() {
int num;
cin>>num;
int nums[num];
for(int i=0;i<num;i++)
cin>>nums[i];
//归并排序调用
mergesort(nums,0,num-1);
for(int i=0;i<num;i++){
cout << nums[i] <<" ";
}
return 0;
}
void mergesort(int arr[],int left,int right){
if(right<=left) return ;
int mid=(left+right)/2;
mergesort(arr,left,mid);
mergesort(arr,mid+1,right);
merge(arr,left,mid,right);
}
void merge(int arr[],int left,int mid,int right){
int temp[right-left+1];
int i=left,j=mid+1,k=0;
while(i<=mid&&j<=right){
temp[k++]=arr[i]<=arr[j]?arr[i++]:arr[j++];
}
while(i<=mid) temp[k++]=arr[i++];
while(j<=right) temp[k++]=arr[j++];
for(int h=0;h<right-left+1;h++){
arr[left+h]=temp[h];
}
}
7.堆排序(时间复杂度o(nlogn))
堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。在c++中使用优先队列进行存储然后进行输出即可完成排序, 排序工作在内部完成的。
附一下c++代码即可:
#include <iostream>
#include <queue>
using namespace std;
void heapsort(int[],int length);
int main() {
int num;
cin>>num;
int nums[num];
for(int i=0;i<num;i++)
cin>>nums[i];
//堆排序
heapsort(nums,num);
for(int i=0;i<num;i++){
cout << nums[i] <<" ";
}
return 0;
}
void heapsort(int arr[],int length){
priority_queue<int, std::vector<int>,greater<int> > q ;
for(int i=0;i<length;i++){
q.push(arr[i]);
}
for(int i=0;i<length;i++){
arr[i] =q.top();
q.pop();
}
}
最后总结一下子:
这些算法里面有复杂的,也有比较容易理解的,主要学习是先理解,看懂代码,然后自己写出代码。
如果在应用过程中追求效率的话,首选归并排序、快速排序、堆排序(空间复杂度低)来解决问题,这几种算法比较难理解,可
以多背多写达到一个灵活应用的水平。
如果不追求效率的话,基本的排序就可以完成,选择排序、插入排序、冒泡排序,基本异曲同工,比较容易理解,按理解写出来
即可。