各种排序算法:交换(冒泡,快速),
选择(直接选择,堆排序),
插入(直接插入,二分插入,希尔排序),
归并排序
1 冒泡排序
2 快速排序 (两种方法)
3 直接选择排序
4 堆排序
5 直接插入排序
希尔排序
二分法排序
6 归并排序
7 分配排序(基数排序,箱排序,计数排序) 没有实现
测试代码
各种算法的复杂度的一个总结
参考:排序算法实现及分析
=================================================================================
冒泡排序:就像气泡一样,当前元素和下一个比,合适就这样,不合适就交换折腾 n * n次
//1 双重循环 ----里面的范围:[0,n-1-i] 比较的是j和j+1 2 每一次都要交换 3 优化代码,加上交换过标志 flag(若flag=false表示排好序); void sort_bubble( int arr[],int num ) { bool flag=true; for(int i=0;i<num-1&&flag;i++) //第 i趟循环: 总共是 n-1趟循环 { flag=false; //遇到 小(大)的数值往后面浮动,先把后面的i个已经排好序了:[0,num-i] [i,num](已经拍好了) for(int j=0;j<num-i;j++) { if(arr[j]<arr[j+1]) { swap_element(arr+j,arr+j+1); flag=true; } } /*printArray(arr,num);*/ } printArray(arr,num); }
快速:元素找到自己的排序位置,当每个人都找到了,那个顺序就定了。
//快速排序(冒泡法的改进:交换排序) 第一次调用 sort_Quick(arr,0,len)--- //一定要把pos隔离出来 //做一趟 快速排序:arr[left] 的位置。 int find_pos( int * arr, int left, int right ) { int low=left,high=right; int tmp=arr[left]; //要找的 数值就保存在这里了,腾空一个位置。 while(low<high) //结束的时候 low==high,也就是需要返回的 值所在的位置。 { while(low<high&&arr[high]>tmp) high--; arr[low]=arr[high]; //把比较小的移动到 low端(或者直接调换顺序开个头) while(low<high&&arr[low]<tmp) low++; arr[high]=arr[low]; //把比较大的移动到high端 } arr[low]=tmp; return low; } int find_pos2(int * arr, int left, int right) { int cmpValue = arr[right]; int theIndex = left; for(int i = left; i < right; ++i) { if(arr[i] < cmpValue) { swap_element(arr+i,arr+theIndex); theIndex++; } } swap_element(arr+theIndex,arr+right); //arr+theIndex是 大于等于arr+right的 return theIndex; } void sort_quick( int arr[],int low,int high ) { int pos; if(low<high) //low==high的时候结束递归。 { /*pos=find_pos(arr,low,high);*/ pos=find_pos2(arr,low,high); sort_quick(arr,low,pos-1); //左边的部分 sort_quick(arr,pos+1,high); //右边的部分 } }
选择:老实的排序法,找到最值,和当前的位置进行交换。
//1 每次取出来 最小的([i+1,n]) 2 和当前的i进行交换(判断j和i是否相等) void sort_select( int arr[],int num ) { int min; //记录下 每一趟排序的 最小的那个下标。 for(int i=0;i<num-1;i++) //i 表示轮到了 哪一个下标的元素 { min=i; for(int j=i+1;j<num;j++) { if(arr[j]<arr[min]) { min=j; } } //找到这一段的最小的值之后,与 arr[i]交换位置。 if(i!=min) { swap_element(arr+i,arr+min); } printArray(arr,num); } }
堆:和选择一样建一个具有堆的性质二叉树(节点永远比子节点大),堆顶就是最值,拿出来,再建一次堆(i-1个)。
//从大到小(或者从小到大)排列:主要考虑的是 p(i) 以及 p.left(2*i-1)或者p.right(2*i)的较小或者较大值----然后交换或者退出
void siftdown( int arr[], int nodeN, int maxN)
{
int tmp=arr[nodeN];
int child=nodeN*2+1,parent=nodeN;
while(child<=maxN)
{
if(child<maxN&&arr[child+1]<arr[child]) //存在右子树序列
{
child=child+1; //得到最小的结点。
}
if(tmp<=arr[child]) break;
else
{
arr[parent] = arr[child];
parent = child; //往 下面的层数进行扩展
child = child*2+1;
}
}
arr[parent]=tmp;
}
// 1 初建堆---符合堆的概念 [n....2],其中 根结点 arr[0]最小
//2 反复调整排序 [n....2]: 选择交换(arr[0],arr[n]),选取最(大)小的(arr[0]).
void sort_stack(int arr[],int num )
{
for(int i=(num-1)/2;i>=0;i--)
{
siftdown(arr,i,num-1);
}
cout<<"最小的元素是:"<<arr[0]<<endl;
for(int n=num-1;n>=1;n--)
{
swap_element(arr,arr+n);
siftdown(arr,0,n-1);
printArray(arr,num);
}
printArray(arr,num);
}
5 插入排序
插入:随便拿一个向有序的中放。
开始只有找一个元素参照,一个必然是有序的,然后可以结合二分法查找,来排序,用查找的思想排序,逆天了
// 排列好的[1,i-1] 没有排列好的部分:[i,n]:只是 找到i这个位置和[1,i-1]比较和交换。
// 1 比较 2 移动(往后面移动),腾出位置来 3 插入到最后的一个位置。
void sort_insert( int arr[],int num )
{
int curValue;
int j;
for(int i=0+1;i<num;i++)
{
curValue=arr[i];
j=i-1;
while(arr[j]>curValue&&j>=0)
{
arr[j+1]=arr[j];
j--;
}
arr[j+1]=curValue;
printArray(arr,num);
}
}
void sort_Binaryinsert( int arr[],int num )
{
int low,high,mid;
int curValue;
for(int i=0+1;i<num;i++)
{
curValue=arr[i];
low=0;
high=i-1;
while(low<=high) //结束条件:low=high+1(即为需要插入的位置); 1 2 4 5 6 3
{
mid=(low+high)/2;
if(arr[mid]<curValue)
{
low=mid+1;
}
else
{
high=mid-1;
}
}
//2 往后面移动和插入数值
for(int j=i-1;j>=high+1;j--)
{
arr[j+1]=arr[j];
}
arr[high+1]=curValue;
printArray(arr,num);
}
}
//其实和 直接插入排序 大致相同,只是间隔gap换成 1就可以了
void sort_shellComplete( int arr[], int num, int gap )
{
int curValue;
int j;
for(int i=0+gap;i<num;i++)
{
curValue=arr[i];
/*j=i-gap;
while(arr[j]>curValue&&j>=0)
{
arr[j+gap]=arr[j];
j-=gap;
}*/
for(j=i-gap;j>=0&&arr[j]>curValue;j=j-gap)
{
arr[j+gap]=arr[j];
}
arr[j+gap]=curValue;
printArray(arr,num);
}
}
void sort_shell( int arr[],int num )
{
for(int i=num/2;i>=1;i=i/2)
{
sort_shellComplete(arr,num,i);
}
}
6 归并:几组有序的合并成一个。很简单,每人轮流拿出一个比较下,放进篮子里不就完了。
void merges( int arr[], int low, int mid, int high )
{
//前半部分:[low,mid] 后半部分:[mid+1,high] 然后分别比较→赋值(再移动即 循环)
int i=low,j=mid+1,k=low; //i,j两个坐标的变化;k--新的组成的数组的下标的变化-- k=0错误
int tmparr[50];
while(i<=mid&&j<=high) //结束条件就是:其中一个条件不满足(其中一个已经用完了)
{
if(arr[i]<arr[j])
{
tmparr[k++]=arr[i++];
}
else
{
tmparr[k++]=arr[j++];
}
}
//好好处理一下的部分
while(i<=mid)
{
tmparr[k++]=arr[i++];
}
while(j<=high)
{
tmparr[k++]=arr[j++];
}
//合并好的 数组元素付给 需要合并的数组。
for(int i=low;i<=high;i++)
{
arr[i]=tmparr[i];
}
}
void sort_ReMerge( int arr[], int low, int high )
{
int mid;
if(low<high) //最后: 单个的元素(low==high) 结束递归。
{
mid=(low+high)/2;
sort_ReMerge(arr,low,mid); //前半段分
sort_ReMerge(arr,mid+1,high); //后半段分
merges(arr,low,mid,high); //前后 两段合并
}
}
void sort_merge( int arr[],int num)
{
sort_ReMerge(arr,0,num-1);
printArray(arr,num);
}
测试代码
void printArray(int arr[],int num)
{
cout<<"排序后的数组元素是:"<<endl;
for(int i=0;i<num;i++)
{
cout<<arr[i]<<endl;
}
}
void swap_element(int *a,int *b)
{
int tmp;
tmp=*a;
*a=*b;
*b=tmp;
}
int main()
{
int arr[]={101,87,25,90,54,21,99,27,76};
int num=sizeof(arr)/sizeof(int);
printArray(arr,num);
//sort_bubble(arr,num);
//sort_quick(arr,0,num-1);
//sort_select(arr,num);
//sort_insert(arr,num);
//sort_shell(arr,num);
//sort_Binaryinsert(arr,num);
//sort_stack(arr,num);
//sort_merge(arr,num);
return 0;
}
====================================================================================
各种算法的复杂度的一个总结
直接选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法,
而冒泡排序、插入排序、归并排序和基数排序是稳定的排序算法。
最好 最坏 平均 稳定 辅助空间
快速排序 O(nlogn) O(n^2) O(nlogn) 否 不要
冒泡排序 O(n) O(n^2) O(n^2) 是 不要
直接选择排序 O(n^2) O(n^2)O(n^2) 否 不要
堆排序 O(nlogn) O(nlogn) O(nlogn) 否 不要
直接插入排序 O(n) O(n^2) O(n^2) 是 不要
希尔排序 O(n) O(n^2) O(n^2) 否 不要
归并排序 O(nlogn) O(nlogn) O(nlogn) 是 要(1.5?)
转载于:https://blog.51cto.com/5037939/1301526