冒泡排序:
一.冒泡排序算法及思路
冒泡排序(bubble sort)是一种交换排序,它的基本思想:两两比较相邻的关键字,如果反序则交换,直到没有反序的记录为止。
冒泡排序是稳定的排序算法。下面看思路:
1.初始状态下,arr[0,n-1]是无序的;
2.第一次扫描(遍历):从无序底部向上依次比较两个相邻的两个气泡的重量,若发现轻者在下,重者在上,则交换两者之间的位置。即依次比较(arr[n-1],arr[n-2]),(arr[n-2],arr[n-3]),…,(arr[1],arr[0])。对于每对气泡(arr[j+1],arr[[j]),如果arr[j+1]<arr[j],那么就交换两者的内容,也就是值。
第一次扫描结束,“最轻“的气泡就会浮到该区间的顶部,即关键字最小的记录被放在最高的位置arr[0]上。
3.第二次扫描:扫描arr[1…n-1]。扫描结束时,”次轻“的气泡漂浮到arr[1]位置上。
4.第i次扫描,arr[[0…i-1]和arr[i…n-1]分别是当前的有序区和无序区。扫描还是从无序区底部向上,直至该区顶部。扫描结束,该区中,最轻的气泡浮到顶部位置arr[i]位置上,结果是a[[0…i-1]变为新的有序区
最后,经过len-1次扫描可以得到有序区arr[0…n-1]。
二.代码实现
#include <iostream>
using namespace std;
//冒泡排序初级版本,又可称为交换排序
void bubblesort1(int arr[],int len)
{
//申请临时变量用于交换
int temp=0;
//对数组进行长度为len-1次的扫描
for(int i=0;i<len-1;++i)
{
//从后往前交换,这样最小值冒泡道开头部分
for(int j=i+1;j<=len-1;++j)
{
if(arr[j]<arr[i])
{
temp=arr[j];
arr[j]=arr[i];
arr[i]=temp;
}
}
}
}
//优化后的冒泡排序,正宗的冒泡排序
void bubblesort2(int arr[],int len)
{
//申请临时变量用于交换
int temp=0;
//对数组进行长度为len-1次的扫描
for(int i=0;i<len-1;++i)
{
//从后往前交换,这样最小值冒泡道开头部分
for(int j=len-1;j>=i;--j)
{
//如果后面一位的元素值小于当前元素值,交换两元素的值 swap(a[j],a[j+1])
if(arr[j+1]<arr[j])
{
temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
}
void bubblesort3(int arr[],int len)
{
//用于标记每次扫描时是否发生交换
int flag=0;
//申请临时变量用于交换
int temp=0;
//对数组进行长度为len-1次的扫描
for(int i=0;i<len-1;++i)
{
//每次交换之前要对flag置0操作
flag=0;
for(int j=len-1;j>=i;--j)
{
//交换两者数据 swap(a[j],a[j+1];
if(arr[j+1]<arr[j])
{
temp=arr[j+1];
arr[j+1]=arr[j];
arr[j]=temp;
//发生交换flag置1操作
flag=1;
}
//这次扫面没有发生交换,说明已经是排序好的,不需要排序,返回
if(flag==0)
{
return;
}
}
}
}
int main()
{
int arr[]={3,7,5,8,1,9,2,6,4};
cout<<"冒泡排序前:"<<endl;
// 打印排序前的数组 printf_array(arr,9);
for(int i=0;i<9;++i)
{
cout<<arr[i]<<" ";
}
cout<<endl;
bubblesort1(arr,9);
cout<<"冒泡排序后:"<<endl;
// 打印排序后的数组printf_array(arr,9);
for(int i=0;i<9;++i)
{
cout<<arr[i]<<" ";
}
cout<<endl;
bubblesort2(arr,9);
cout<<"冒泡排序后:"<<endl;
// 打印排序后的数组printf_array(arr,9);
for(int i=0;i<9;++i)
{
cout<<arr[i]<<" ";
}
cout<<endl;
bubblesort3(arr,9);
cout<<"冒泡排序后:"<<endl;
// 打印排序后的数组printf_array(arr,9);
for(int i=0;i<9;++i)
{
cout<<arr[i]<<" ";
}
cout<<endl;
return 0;
}
三.时间复杂度分析
最好情况:没有进行数据交换,O(N);
最坏情况:排序表是逆序的,O(N^2)
堆排序:
堆排序具有下列完全性质的完全二叉树:每个结点的值都大于或等于其左右孩子的结点的值称之为大顶堆;每个结点的值都小于其左右孩子结点的值称之为小顶堆。
小顶堆
大顶堆
一. 排序算法及其思路:
堆排序(heap sort)就是利用堆(这里用大顶堆)进行排序的方法。基本思路是:将待排序的序列构成一个大顶堆。此时,整个序列的最大值就是堆顶的根结点。将它移走(其实就是将其与堆数组的末尾元素交换,此时末尾元素就是最大值),然后将剩余的n-1个序列重新构成一个堆,这样就会得到n个元素的次大值。如此反复进行,便可以得到一个有序序列了。
二.代码实现
把堆进行向下调整的代码及图片:
图 堆排序自顶向下过程
图 堆排序自顶向下结果
//向下调整方法(自顶向下),堆排序完的结果不是二叉搜索树,存在右结点比左结点小,父结点是最小的
//传入一个需要向下调整的结点编号i,这里传入1, 即从堆的顶点开始
void siftdown(int i)
{
//flag是用来标及是否向下调整
int flag=0;
int t=0;
//当i结点有儿子时(至少有左儿子的情况下)并且有需要继续调整的时候,循环就执行
while(1*2<=n&&flag==0)
{
//首先判断它和左儿子的关系,并且用t记录值较小的结点编号
if(h[i]>h[i*2])
{
t=i*2;
}
else
{
t=i;
}
//如果它有右儿子,再对右儿子进行讨论
if(i*2+1<=n)
{
if(h[t]>h[i*2+1])
{
t=i*2+1;
}
}
//如果发现最小的结点编号不是自己,说明子结点中有比父结点更小的;意思就是父结点和左右孩子结点的值进行比较,最小的放在最上面
if(t!=i)
{
//申请临时变量用于交换,等同于swap(h[i],h[t])
int temp=h[i];
h[i]=h[t];
h[t]=temp;
//更新i为刚才与他交换的儿子结点的编号,便于接下来继续向下调整
i=t;
}
else
{
//否则说明当前的父结点已经比两个子结点都要小了,不需要再进行调整了
flag=1;
}
}
}
把堆进行向上调整的代码及图片:
图 堆排序自底向上过程
图 堆排序自底向上结果
//向上调整方法(自底向上),堆排序完的结果不是二叉搜索树,存在右结点比左结点小,父结点是最小的
//传入一个需要向上调整的结点编号i
void siftup(int i)
{
//用来标记是否向上调整
int flag=0;
int t=0;
//如果i在堆顶就返回,不需要调整
if(i==1)
{
return;
}
//如果i不在堆顶,并且当前结点的值比父亲结点的值还要小,就继续向上调整
while(i!=1&&flag==0)
{
//判断当前节点的值是否比父亲结点的值要小,如果小就交换,swap(h[i],h[i/2])
if(h[i]<h[i/2])
{
int temp=h[i];
h[i]=h[i/2];
h[i/2]=temp;
}
else
{
//更改标识,表示不需要调整了,当前结点的值要比父亲结点的值要大
flag=1;
}
//更新编号i为父亲结点的编号,为了便于下一次继续向上调整
i=i/2;
}
return;
}
建立堆的代码:
(1)自顶向下
//建立堆 自顶向下
void creat()
{
int n=0;
for(int i=1;i<=m;++i)
{
++n;
h[n]=a[i]; //或者可以这样写:scanf("%d",&h[n]);
siftup(n);
}
}
(2)自底向上
//建立堆 自底向上
void creat()
{
for(int i=n/2;i>=1;--i)
{
siftdown(i);
}
}
删除最小元素的函数代码:
//删除最小元素的函数
//可用于打印堆从小到大的排序
int deletemin()
{
//用临时变量来记录堆顶点的值
int temp=h[1];
//把堆的最后一个结点的值赋值给堆顶点
h[1]=h[n];
//堆的元素个数减1
--n;
//向下调整
siftdown(1);
//返回之前记录堆顶点最小的值
return temp;
}
建立堆以及堆排序完整的代码如下:
//建立堆以及堆排序代码如下
#include <iostream>
using namespace std;
//用来存放堆的数组
int h[101];
//用来存储堆堆中元素的个数,也就是堆的大小
int n;
//交换函数,用来交换堆排序里面两个元素的值
void swap(int x,int y)
{
int temp=h[x];
h[x]=h[y];
h[y]=temp;
return;
}
//向下调整函数(自顶向下)
//传入一个需要向下调整的结点编号i,这里传入i,即从堆的顶点开始向下调整
void siftdown(int i)
{
//存放较小值得结点编号,交换元素的下标
int t;
//flag是用来标记是否需要继续向下调整
int flag=0;
//当i结点有儿子时(其实是至少有左儿子)并且有需要继续向下调整的时候循环就执行
while(i*2<=n&&flag==0)
{
//首先判断它和左儿子的关系,并用t记录值较小的结点编号
if(h[i]>h[i*2])
{
t=i*2;
}
else
{
t=i;
}
//如果它有右儿子,再对儿子进行讨论
if(i*2+1<=n)
{
//如果右儿子的值更小,更新较小的结点编号
if(h[t]>h[i*2+1])
{
t=i*2+1;
}
}
//如果发现最小的结点编号不是自己,说明子结点有比父结点更小的
if(t!=i)
{
//交换两者的值,swap(h[i],h[t])
int temp=h[t];
h[t]=h[i];
h[i]=temp;
}
//否则说明当前的父结点已经比两个子结点都要小了,不需要再进行调整了
else
{
flag=1;
}
}
return;
}
//建立堆函数
void creat()
{
//从最后一个非叶结点到第1个结点依次进行向下调整
for(int i=n/2;i>=1;--i)
{
siftdown(i);
}
return;
}
//删除最小元素的函数
//可用于打印堆从小到大的排序
int deletemin()
{
//用临时变量来记录堆顶点的值
int temp=h[1];
//把堆的最后一个结点的值赋值给堆顶点
h[1]=h[n];
//堆的元素个数减1
--n;
//向下调整
siftdown(1);
//返回之前记录堆顶点最小的值
return temp;
}
int main()
{
int i;
int num;
//输入元素的个数
cout<<"请输入数字:"<<endl;
cin>>num;
//循环输入元素
cout<<"请输入元素的数字"<<endl;
for(int i=1;i<=num;++i)
{
cin>>h[i];
}
//输出没有堆排序的元素
cout<<"输出堆排序之前的元素:"<<endl;
for(int i=1;i<=num;++i)
{
cout<<h[i]<<" ";
}
cout<<endl;
n=num;
creat();
//输出堆排序之后的元素
cout<<"输出堆排序之后的元素:"<<endl;
for(int i=1;i<=num;++i)
{
cout<<deletemin()<<" ";
}
cout<<endl;
return 0;
}
改进后的堆排序:
从小到大排序的时候不是建立最小堆而是最大堆,最大堆建立好之后,最大的元素再h[1],因为我们的需求是从小到大排序,最大的放在最后。所以我们将h[1]和h[n]交换,此时h[n]就是数组的最大元素。交换后,还需要把h[1]向下调整以保持堆的特性。循环反复,直到堆的大小变为1为止。此时数组h中的数就已经是排序好的了。
改进后的堆排序代码如下:
//建立堆以及改进后的堆排序代码如下
#include <iostream>
using namespace std;
//用来存放堆的数组
int h[101];
//用来存储堆堆中元素的个数,也就是堆的大小
int n;
//交换函数,用来交换堆排序里面两个元素的值
void swap(int x,int y)
{
int temp=h[x];
h[x]=h[y];
h[y]=temp;
return;
}
//向下调整函数(自顶向下)
//传入一个需要向下调整的结点编号i,这里传入i,即从堆的顶点开始向下调整
void siftdown(int i)
{
//存放较小值得结点编号,交换元素的下标
int t;
//flag是用来标记是否需要继续向下调整
int flag=0;
//当i结点有儿子时(其实是至少有左儿子)并且有需要继续向下调整的时候循环就执行
while(i*2<=n&&flag==0)
{
//首先判断它和左儿子的关系,并用t记录值较小的结点编号
if(h[i]>h[i*2])
{
t=i*2;
}
else
{
t=i;
}
//如果它有右儿子,再对儿子进行讨论
if(i*2+1<=n)
{
//如果右儿子的值更小,更新较小的结点编号
if(h[t]>h[i*2+1])
{
t=i*2+1;
}
}
//如果发现最小的结点编号不是自己,说明子结点有比父结点更小的
if(t!=i)
{
//交换两者的值,swap(h[i],h[t])
int temp=h[t];
h[t]=h[i];
h[i]=temp;
}
//否则说明当前的父结点已经比两个子结点都要小了,不需要再进行调整了
else
{
flag=1;
}
}
return;
}
//建立堆函数
void creat()
{
//从最后一个非叶结点到第1个结点依次进行向下调整
for(int i=n/2;i>=1;--i)
{
siftdown(i);
}
return;
}
//堆排序
void heapsort()
{
while(n>1)
{
swap(1,n);
--n;
siftdown(1);
}
return;
}
int main()
{
int i;
int num;
//输入元素的个数
cout<<"请输入数字:"<<endl;
cin>>num;
//循环输入元素
cout<<"请输入元素的数字"<<endl;
for(int i=1;i<=num;++i)
{
cin>>h[i];
}
//输出没有堆排序的元素
cout<<"输出堆排序之前的元素:"<<endl;
for(int i=1;i<=num;++i)
{
cout<<h[i]<<" ";
}
cout<<endl;
n=num;
creat();
//输出堆排序之后的元素
cout<<"输出堆排序之后的元素:"<<endl;
for(int i=1;i<=num;++i)
{
cout<<h[i]<<" ";
}
cout<<endl;
return 0;
}
三.时间复杂度分析
最好情况:O(NlogN)
最坏情况:O(NlogN)
平均情况:O(NlogN)
快速排序
一.快速排序算法及思路:
快速排序(quick soer)的基本思想:通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可份别对这两部分记录进行排序,已达到整个序列有序的目的。
三.代码实现
//快速排序
#include <iostream>
using namespace std;
void quicksort(int arr[],int left,int right)
{
int i;
int j;
int pivot;
if(left>right)
{
return;
}
if(left<right)
{
//pivot存基准数
pivot=arr[left];
i=left;
j=right;
while(i<j)
{
//要从右边开始,这点很重要,别忽略了
while(i<j&&arr[j]>=pivot)
{
--j;
}
if(i<j)
{
//把比pivot小的元素移到左边
arr[i++]=arr[j];
}
while(i<j&&arr[i]<=pivot)
{
++i;
}
if(i<j)
{
//把比pivot大的元素移到右边
arr[j--]=arr[i];
}
}
//pivot移到最终位置
arr[i]=pivot;
//继续处理左边的,对左区间进行递归排序
quicksort(arr,left,i-1);
//继续处理右边的,对右区间进行递归排序
quicksort(arr,i+1,right);
}
}
int main()
{
int arr[9]={6,2,7,9,3,1,5,4,8};
//快速排序之前
cout<<"快速排序之前:"<<endl;
for(int i=0;i<9;++i)
{
cout<<arr[i]<<" ";
}
cout<<endl;
quicksort(arr,0,8);
//快速排序之前后
cout<<"快速排序之后:"<<endl;
for(int i=0;i<9;++i)
{
cout<<arr[i]<<" ";
}
cout<<endl;
}
这里的pivot代表的是基准值,它的初始值为a[left]。局部变量i和j分别代表left和right的位置。接着按照下面的步骤进行一趟交换:
(1)把比pivot小的元素移到低端(left);
(2)把比pivot大的元素移到高端(high);
(3)pivot移到最终位置,此时这个位置的左边元素的值都要比pivot小,而右边的元素的值都要比pivot大。
(4)对左边,右边分别进行递归排序。从而把前三步的排序慢慢细化,直到left和right交汇。
三.时间复杂度分析
最好:O(NlogN)
最坏:O(N^2)
平均:O(NlogN)
归并排序
一.归并排序的算法及思路:
归并排序(merge sort)是利用归并的思想实现的排序的方法。它的原理是假设初始序列含有n个记录,则可以看成是n个有序的子序列,每个子序列的长度为1,然后两两归并,得到[n/2],([x表示不小于x的最小整数)个长度为2或1的有序子序列;再两两归并, … ,如此重复,直至得到一个长度为n的有序序列为止,这种方法成为二路归并排序。
二.代码实现:
//归并排序
#include <iostream>
using namespace std;
void merge(int a[],int temp[],int left,int mid,int right)
{
int i=left;
int j=mid+1;
int k=left;
//比较两边的数组,把较小的数组元素的值放入临时数组temp中
while (k<=right)
{
if(i>mid)
{
temp[k++]=a[j++];
}
else if(j>right)
{
temp[k++]=a[i++];
}
else
{
//把右边剩余的元素放进temp数组中
if(a[i]>a[j])
{
temp[k++]=a[j++];
}
//把左边剩余的元素放进temp数组中
else
{
temp[k++]=a[i++];
}
}
}
//把临时数组复制到原始数组
for(int k=left;k<=right;k++)
{
a[k]=temp[k];
}
}
void merge_sort_helper(int a[],int temp[],int left,int right)
{
//结束条件,原子结点return
if(left>=right)
{
return;
}
//计算分裂点
int mid=left+(right-left)/2;
//对左区间用递归做归并排序
merge_sort_helper(a,temp,left,mid);
//对左区间用递归做归并排序
merge_sort_helper(a,temp,mid+1,right);
//组合,把左右两个有序区间合并为一个有序区
merge(a,temp,left,mid,right);
}
void merge_sort(int a[], int len)
{
//分配临时数组
int *temp=new int[len];
//调用merge_sort_helper函数进行归并排序
merge_sort_helper(a,temp,0,len-1);
//释放临时数组内存
delete[] temp;
}
int main(int argc, const char * argv[])
{
int a[9]= {3,5,7,2,8,9,1,6,4};
cout<<"归并排序前:"<<endl;
for(int i=0;i<9;++i)
{
cout<<a[i]<<" ";
}
cout<<endl;
merge_sort(a,9);
cout<<"归并排序后:"<<endl;
for(int i=0;i<9;++i)
{
cout<<a[i]<<" ";
}
cout<<endl;
return 0;
}
非递归排序代码如下:
```cpp
//非递归归并排序算法,自底向上
#include<iostream>
using namespace std;
//在原始数组上进行操作,
void merge(int arr[], int low, int mid, int high)
{
int i,j,k;
//low为第一个有序区的第一个元素
i=low;
//mid+1为第二个有序区的第一个元素
j=mid+1;
k=0;
int *temp=new(nothrow)int[high-low+1];
if(!temp)
{
cout << "内存分配失败"<< endl;
return;
}
//依次比较两个有序序列的第一个元素,将较小的一方存放到temp数组中
while(i<=mid&&j<=high)
{
if(arr[i]<arr[j])
{
temp[k++] = arr[i++];
}
else
{
temp[k++] = arr[j++];
}
}
while (i <= mid)
temp[k++] = arr[i++];
while (j <= high)
temp[k++] = arr[j++];
//将排好序的存回arr中low到high该区间内
for(i=low,k=0;i<= high;i++,k++)
arr[i] = temp[k];
//删除指针,由于指向的是数组,必须用delete[]
delete[]temp;
}
//非递归合并排序函数:根据步长size大小先处理数组中两两相邻的序列,合并后成倍扩大size,进入下一轮的合并排序
void mergeSort(int arr[], int n)
{
//非递归法实现归并排序, 形参n表示为数组中的元素个数
int size=1,low,mid,high;
while(size <= n)
{
low=0;
while (low+size<=n)
{
mid=low+size-1;
high=mid+size;
if (high>n)
{
high=n;
}
merge(arr,low,mid,high);
low=high+1;
}
size=size*2;
}
}
int main()
{
int a[9]={4,2,7,5,8,9,3,1,6};
int n=sizeof(a)/sizeof(int);
//非递归归并排序前
cout<<"非递归归并排序前:"<<endl;
for (int i=0;i<n;i++)
{
cout << a[i] << " ";
}
cout<<endl;
mergeSort(a,n-1);
//非递归归并排序后
cout<<"非递归归并排序后:"<<endl;
for (int i=0;i<n;i++)
{
cout << a[i] << " ";
}
cout<<endl;
return 0;
}
三.时间复杂度分析
最好:O(NlogN)
最坏:O(NlogN)
平均:O(NlogN)
桶排序
一.桶排序的算法及思路:
桶排序(bucket sort),基本思想是:设置若干个桶子,依次扫描待排序的记录A[0],A[1], … ,A[n-1],把关键字等于k的记录全都装入到第k个箱子里(分配),然后按照序号依次将非空的桶子依序连接起来(收集)。
二.代码实现
//桶排序计数方法
#include <iostream>
using namespace std;
int main()
{
int a[9];
int t;
for(int i=0;i<9;++i)
{
//对数字出现的次数全部初始化为0
a[i]=0;
}
//循环读入9个数
for(int i=0;i<9;++i)
{
//把每一个数读进变量t中
cin>>t;
//进行计数
a[t]++;
}
//依次判断a[0]至a[9]
for(int i=0;i<9;++i)
{
//c出现几次就打印几次
for(int j=0;j<a[i];++j)
{
cout<<i<<" ";
}
}
return 0;
}
三.时间复杂度分析
最好:O(N)
最坏:O(NlogN)
平均:O(N+M)
选择排序
一.选择排序的算法及思路
直接插入排序是稳定的排序算法。直接插入排序的基本思想:假设待排序的记录存放再数组A[0…n-1]中。初始时,A[0]自成一个排序区,无序区为R[2…n]。从i=1起直到i=n-1为止,依次将A[I]插入当前对的有序区R[0…I-1] 中,生成含n个记录的有序区。
二.代码实现
//直接插入排序算法
#include <iostream>
using namespace std;
void insertsort(int a[],int len)
{
int temp;
int j,i;
//需要选择len-1次
for(i=1;i<len;++i)
{
//暂时存放下标为i的数。下标从1开始,因为开始时,下标为0的数,前面没有任何数,此时被认为是排好序的数
temp=a[i];
for(j=i-1;temp<a[j]&&j>=0;--j)
{
//如果条件满足就往后挪。最坏的情况是temp比a[0]小,它要放在最前面
a[j+1]=a[j];
}
//找到下标为i的数的存放位置
a[j+1]=temp;
}
}
int main()
{
int a[9]={3,7,1,8,4,9,5,6,2};
//直接插入排序前
cout<<"直接插入排序前:"<<endl;
for(int i=0;i<9;++i)
{
cout<<a[i]<<" ";
}
cout<<endl;
insertsort(a,9);
//直接插入排序后
cout<<"直接插入排序后:"<<endl;
for(int i=0;i<9;++i)
{
cout<<a[i]<<" ";
}
cout<<endl;
return 0;
}
三.时间复杂度分析
最好:O(N)
最坏:O(N^2)
平均:O(N^2)
希尔排序
一.希尔排序的算法及思路
希尔排序算法(shell sort)是属于插入排序,是不稳定的排序方法。
希尔排序基本思想:希尔排序算法先将要排序的一组数按照某个增量d分成若干组,每组中记录的下标差d对每组全部元素进行排序,然后用一个较小的增量对它进行再次分组,并对每个新数组重新进行排序。当增量减到1时,整个要排序的数被分成一组,排序完成。所以,希尔排序属于一种的分组插入方法。
二.代码实现
//希尔排序算法实现
#include <iostream>
using namespace std;
void shellsort(int a[],int len)
{
int i;
int j;
int temp;
int t;
//控制增量
for(t=len/2;t>0;t=t/2)
{
//这个for循环就是前面的直接插入排序
for(i=t;i<len;++i)
{
temp=a[i];
for(j=i-t;j>=0&&temp<a[j];j=j-t)
{
a[j+t]=a[j];
}
a[j+t]=temp;
}
}
}
int main()
{
int a[9]={4,3,5,2,9,1,7,6,8};
//希尔插序前
cout<<"希尔排序前:"<<endl;
for(int i=0;i<9;++i)
{
cout<<a[i]<<" ";
}
cout<<endl;
shellsort(a,9);
//希尔排序后
cout<<"希尔排序后:"<<endl;
for(int i=0;i<9;++i)
{
cout<<a[i]<<" ";
}
cout<<endl;
return 0;
}
三.时间复杂度分析:
最好:O(Nlog n~N^2)
最坏:O(N^1.5)
平均:O(N^2)
选择排序
一.选择排序的算法及思路
选择排序(select sort),就是通过n-i次关键字的比较,从n-i+1个记录中选出关键字最小的记录,并和第i(1<=i<=n)个记录交换之。
二.代码实现
#include <iostream>
using namespace std;
void selectsort(int a[],int len)
{
int min;
for(int i=0;i<len;++i)
{
//将当前下标定义为最小值下标
min=i;
//循环之后的数据
for(int j=i+1;j<len;++j)
{
//如果有小于当前最小值的关键字
if(a[min]>a[j])
{
//将关键字的下标赋值给min
min=j;
}
}
//如果i不等于i,说明找到最小值,交换两者的值,swap(a[i],a[min])
if(i!=min)
{
int temp=a[i];
a[i]=a[min];
a[min]=temp;
}
}
}
int main()
{
int a[9]={5,3,7,6,1,9,4,2,8};
//选择插序前
cout<<"选择排序前:"<<endl;
for(int i=0;i<9;++i)
{
cout<<a[i]<<" ";
}
cout<<endl;
selectsort(a,9);
//选择排序后
cout<<"选择排序后:"<<endl;
for(int i=0;i<9;++i)
{
cout<<a[i]<<" ";
}
cout<<endl;
return 0;
}
三.时间复杂度分析
最好:O(N^2)
最坏:O(N^2)
平均:O(N^2)
排序算法总结
排序方法 | 最好情况 | 最坏情况 | 平均情况 | 空间复杂度 | 稳定性 |
---|---|---|---|---|---|
冒泡排序 | O(N) | O(N^2) | O(N^2) | O(1) | 稳定 |
堆排序 | O(NlogN) | O(NlogN) | O(NlogN) | O(1) | 不稳定 |
快速排序 | O(NlogN) | O(N^2) | O(NlogN) | O(logN)~O(N) | 不稳定 |
归并排序 | O(NlogN) | O(NlogN) | O(NlogN) | O(n) | 稳定 |
桶排序 | O(N) | O(NlogN) | O(N+M) | O(1) | 稳定 |
直接插入排序 | O(N) | O(N^2) | O(N^2) | O(1) | 稳定 |
希尔排序 | O(N^1.5) | O(N^2) | O(NlogN)~O(N^2) | O(1) | 不稳定 |
选择排序 | O(N^2) | O(N^2) | O(N^2) | O(1) | 不稳定 |