几种常见简单排序算法

- 简单选择排序
循环遍历整个数组,每次遍历都是从当前待填充位置开始,找出未排序集合中的最小值,每次找到更小值都记录其值和位置信息,遍历完成后,将最小值与当前待填充点 进行交换(也就是说需要同时保留着两个位置信息,一个为当前待填充位置,一个是搜索到的待交换位置,如果是指针则需要两个指针)。继续下一个位置,直到外循环到达数组尾。

#include <iostream>
using namespace std;
int main()
{
    int a[10]={23,11,6,33,14,99,23,2,14,20};
    int smallest;
    int smallpos;
    for(int i=0;i<10;i++)
    {
        cout<<a[i]<<' ';
    }
    for(int i=0;i<9;i++)
    {
        smallest=a[i];
        smallpos=i;
        for(int j=i+1;j<10;j++)
        {
            if(a[j]<smallest)
            {
                smallest=a[j];
                smallpos=j;
            }
        }
        a[smallpos]=a[i];
        a[i]=smallest;
    }
    cout<<endl;
    for(int i=0;i<10;i++)
    {
        cout<<a[i]<<' ';
    }
    return 1;
}

- 插入排序
插入排序的原理为在未排序集合中选择一个值在已排序集合中寻找其合适的位置插入。首先整个集合默认为未排序集合,从头开始遍历,得到一个未排序数据并记录,然后从该数据位置开始往回遍历寻找插入位置,首先判断待插入位置是否为首位,如果是则直接插入。否则,每次将待插入值与待插入位置前一位的值相比,若比待插入值大,则该值往后移动一位,待插入位置前移一位,否则将待插入值填入待插入位置。

#include <iostream>
using namespace std;
/******插入排序***********/
int main()
{
    int a[10]={23,11,6,33,14,99,23,2,14,20};
    int cur;
    for(int i=0;i<10;i++)
    {
        cout<<a[i]<<' ';
    }
    cout<<endl;
    for(int i=1;i<10;i++)
    {
        cur=a[i];
        for(int j=i;j>=0;j--)
        { 
            if(j==0)
            {
                a[j]=cur;
            }
            else if(a[j-1]>cur)
            {
                a[j]=a[j-1];
            }
            else
            {
                a[j]=cur;
                break;
            }
        }
     } 
    for(int i=0;i<10;i++)
    {
        cout<<a[i]<<' ';
    }
    return 1;
}

-交换排序

循环遍历数组,每次比较相邻两个元素,将大的放在后面,小的放在前面,直到达到最后交换元素位置,每次达到最后交换元素位置并完成交换后,就将最后交换元素位置前移一位。直至最后交换元素位置与首位重合,则排序结束,退出循环。
下面程序中last表示最后交换元素的位置。

#include <iostream>
using namespace std;
/*******交换排序***********/
int main()
{
    int a[10]={23,11,6,33,14,99,23,2,14,20};
    int last=9;
    for(int i=0;i<10;i++)
    {
        cout<<a[i]<<' ';
    }
    cout<<endl;
    while(last>0)
    {
        for(int i=0; i < last; i++ )
        {
            if(a[i]>a[i+1])
            {
                int tmp=a[i];
                a[i]=a[i+1];
                a[i+1]=tmp;
            }
        }
        last--;
    }
    for(int i=0;i<10;i++)
    {
        cout<<a[i]<<' ';
    }   
    return 1;
}

-归并排序
其原理是,将两个有序集合同时遍历,每次比较两个集合中当前位置的元素,将较小的元素赋给合并集合相应位置,然后合并集合待填充位置右移一位,较小元素所在集合当前位置右移一位,继续比较,同时还需要判断哪个集合先遍历完,对于另外一个还有剩余元素的集合,则直接把剩余的元素直接赋给合并集合剩余的位置中。但是由于集合是乱序的,因而需要将集合不断分割至单元素集合(可认为是有序集合),然后再进行集合的的重新组合,组合得到的新集合则是有序的,如此回溯直至回到从原始集合中分开的两个子集为有序集合,再进行最后一次合并,完成原始集合的排序。
总体而言,其步骤是递归地分割原始集合,直至集合中只有单元素,然后往回结合成有序集合,即排序的过程是从下往上的。

#include <iostream>
using namespace std;
int mergesort(int* array,int i,int j);
int merge(int* arr,int i,int  k,int j);
int main()
{
    int a[10]={23,11,6,33,14,99,23,2,14,20};
    int n=9;
    for(int i=0;i<=n;i++)
    {
        cout<<a[i]<<' ';
    }
    cout<<endl;
    mergesort(a,0,n);
    for(int i=0;i<=n;i++)
    {
        cout<<a[i]<<' ';
    }
    return 1;
}
int mergesort(int* array,int i,int j)
{
    if(i<j)      //数组中只剩下一个元素的返回条件
    {
        int k=(i+j)/2 ;
        mergesort(array,i,k);
        mergesort(array,k+1,j);
        merge(array,i,k,j);   //对两个有序自己进行排序
    }
    return 0;
}
int merge(int* arr,int i,int k,int j)
{
    int ipos=i;      //用于遍历左集合
    int kpos=k+1;   //用于遍历右集合
    int mpos=0;     //额外分配的空间位置
    int* tmparr=new int[j-i+1];  //额外分配空间存储排序数组
    while(ipos<=k || kpos<=j)
    {
        if(ipos>k)            //表示左集合数据合并完毕 
        {
//若左集合已经没有元素而右集合还有,直接将右集合元素复制到剩余空间中
            while(kpos<=j)
            {
                tmparr[mpos]=arr[kpos];
                kpos++;
                mpos++;
            }
            continue;
        }
        else if(kpos>j)        //右集合数据合并完毕 
        {
//同理,右集合没有元素了,左集合还有,则把剩下元素直接复制到额外空间
            while(ipos<=k)
            {
                tmparr[mpos]=arr[ipos];
                ipos++;
                mpos++;
            }
            continue;
        }       
        if(arr[ipos]<arr[kpos])
        {
             tmparr[mpos]=arr[ipos];
             ipos++;
             mpos++;
        }
        else
        {
            tmparr[mpos]=arr[kpos];
            kpos++;
            mpos++;
        }
    }
    ipos=i;
    int tmpi=0;
    while(ipos<=j)
    {
        arr[ipos]=tmparr[tmpi];
        ipos++;
        tmpi++;
    }
    delete tmparr;
    return 0;
}

这里写图片描述
图中箭头序号表示的是执行顺序,实现框为原始数据顺序,虚线框为排序过后顺序。

-快速排序
快速排序与归并排序有点相似,都是需要分割,但是其过程却是相反的,归并排序是先分割,然后回溯时候进行排序,当回溯到原集合的时候完成排序。而快速排序是先排序(确定基准元素位置,以及其他元素所处集合)然后分割,再确定分割后的集合中基准元素位置,递归进行,当分割至最后一个元素则意味着最后一个元素的位置确定了,即整个集合完成排序。
算法步骤:
1、从序列中选出一个元素(此处挑选序列第一个元素),作为pivot(基准元素);
2、数组重新排列,将小于基准值的放在基准前面,大于基准值的放在基准后面,重新排列完成后,基准将会被放在其正确的位置,也就是说,这一步骤实际上可以认为是确认了pivot元素的正确位置的。具体做法就是,分别从右、从左开始遍历序列,当在右边遇到小于基准值的则停下,左边遇到大于基准值的则停下,然后二者进行交换,直至二者相遇停止。
3、当确认了pivot的正确位置之后,则可以通过该基准值,将整个序列进行“分割”,然后对“分割”的序列再进行排序,即回到步骤1,只是排序序列为“分割”后的序列,递归进行,分别对基准左右两边的序列作为递归序列。

#include <iostream>
using namespace std;

int qsort(int* array,int l,int r);
int sort(int* array,int lp,int rp);

int main()
{
    int a[10]={23,11,6,33,14,99,23,2,14,20};
    for(int i=0;i<10;i++)
    {
        cout<<a[i]<<' ';
     }
     cout<<endl;
    qsort(a,0,9);
    for(int i=0;i<10;i++)
    {
        cout<<a[i]<<' ';
    }
    return 1;
}

int qsort(int* array,int l,int r )
{
    int pos;
    if(l<r)
    {
        pos=sort(array,l,r);
        qsort(array,l,pos-1);
        qsort(array,pos+1,r);
    }
}
//确定基准的位置
int sort(int* array,int lp,int rp)
{
    int lpos=lp;
    int rpos=rp; 
    int pivot=array[lp];
    while(lpos<rpos)
    {
        while(array[rpos]>pivot)
                rpos--;
        while( (lpos<rpos) && array[lpos]<=pivot)
        {
                lpos++;
        }
        if(lpos<rpos)
        {
            int tmp=array[lpos];
            array[lpos]=array[rpos];
            array[rpos]=tmp;
            lpos++;
            rpos--;
            continue;
        }
     }
     array[lp]=array[rpos];
     array[rpos]=pivot;
     return rpos;
}
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

弹指间LDL

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值