C++笔记:排序算法(冒泡、插入、选择、快速、归并)

void swap(int* a,int* b)
{
    int tmp=*a;
    *a=*b;
    *b=tmp;
}

1、冒泡采用依次比较相邻两个元素大小的方法进行排序,代码如下:
/从小到大排序/

bool SortByBubble(int* pFirst,int* pEnd)
{
     //1、参数合法性检查
    if(pFirst == NULL || pEnd ==NULL || pEnd-pFirst<=0)
        return false;

    bool bChange=false;

    //2、挪动pEnd到最后一个元素的下一位置
    pEnd=pEnd+1;
    do{
        //3、初始指针位置为第2个元素
        int* p=pFirst+1;
        bChange=false;
        //4、比较相邻元素 只要后面的元素比前面的小 ,就交换位置,直到最后一个元素
        while(p<pEnd)
        {
            if(*(p)<*(p-1))
            {
                swap(p-1,p);
                bChange=true;
            }
            ++p;
        }
        //5、循环完之后 ,最后一个元素为最大,所以把最后一个位置往前挪一下(此步骤可稍微提高一点效率)
        --pEnd;
    }while(bChange);
    return true;
}

2、插入法
先排前两个,第三个数在已排好的前两个中找到适当位置插入,这样就排好了前三个,第四个在已排好的前三个中找到位置插入。。。依次下去,直到最后一个数。

bool SortByInsert(int* pFirst,int* pEnd)
{
 //1、参数合法性检查
    if(pFirst == NULL || pEnd ==NULL || pEnd-pFirst<=0)
        return false;
 //2、获取个数
    int n=pEnd-pFirst+1;
//3、从第1个元素开始,每次从右向左看,暂存最右边的这个数,只要在它左边的数比它大,则挪动一个位置
    for(int i=1;i<n;++i)
    {
        int j=i;
        int nTmp=pFirst[i];
        for(;j>0 && pFirst[j-1]>nTmp; --j)
            pFirst[j]=pFirst[j-1];
        //4、此处j的最小值为0
        pFirst[j]=nTmp;
    }

    return true;
}

3、选择法
一种选择:假定位置0此刻为最小的数 ,然后从位置1开始每次只要找到比位置0小的数就是该数交换位置,直到最后一个元素,此时位置0为真正最小的数,下一次假定位置1为最小的数,从位置2开始只要找到比位置1小的数就是该数交换位置,直到最后一个元素。。。依次类推
另一种选择:假定位置0此刻为最小的数,然后从位置1开始每次只要找到比位置0小的数就暂存该数,直到最后一个元素,最后,暂存的这个数与位置0这个数做比较,如果比它小,则交换位置,下一次假定位置1为最小的数,从位置2开始只要找到比位置1小的数就是暂存该数,直到最后一个元素,最后,暂存的这个数与位置1这个数做比较,如果比它小,则交换位置。。。依次类推
第一种代码:

bool SortByLikeChose(int* pFirst,int* pEnd)
{
   //1、参数合法性检查
    if(pFirst == NULL || pEnd ==NULL || pEnd-pFirst<=0)
        return false;
 //2、获取个数
    int n=pEnd-pFirst+1;

    for(int i=0;i<n;++i)
    {
        //3\从i+1到最后一个元素 找最小的放在i处
        for(int j=i+1;j<n;++j)
        {
            if(pFirst[j]<pFirst[i])
                swap(&pFirst[i],&pFirst[j]);
        }
    }
    return true;
}
 第二种代码: 


  bool SortByChose(int* pFirst,int* pEnd)
{
 //1、参数合法性检查
    if(pFirst == NULL || pEnd ==NULL || pEnd-pFirst<=0)
        return false;

    int* pCurPos=pFirst;

    while(pCurPos!=pEnd)
    {
    //2、暂存当前的最小值及最小值所在位置
        int nTmpMin=*pCurPos;
        int* pMin=pCurPos;
 //3、从当前位置的后一个位置开始搜索
        int* pTmp=pCurPos+1;

        while(pTmp<=pEnd)
        {
            if(*pTmp<nTmpMin)
            {
                nTmpMin=*pTmp;
                pMin=pTmp;
            }
            ++pTmp;
        }
         //4、如果最小值的位置与当前位置不是同一位置,则表明最小值发生改变,交换两个数 。
        if(pCurPos!=pMin)
            swap(pMin,pCurPos);
         //5、挪动当前位置到下一处
        ++pCurPos;
    }
    return true;
}

4、快速法
选择中间位置的数作为分界点,,分别从左和从右搜索,,左边只有比分界值小的数则保留,如果遇到大于等于分界值的数则停止并等待,右边只有比分界值大于或等于的数则保留,如果遇到比分界值小的数则等待,此时交换左右两边的数,在交换之前需满足 左边指示的位置必须小于右边的指示位置。 将左半部分递归之前的方法 ,右边也递归之前的方法,代码如下:

       bool SortByQuick(int* pFirst,int* pEnd)
{
     //1、参数合法性检查(包含终止条件 ,如果只剩一个元素 则不继续)
    if(pFirst == NULL || pEnd ==NULL || pEnd-pFirst<=0)
        return false;
   //2、获取个数
    int n=pEnd-pFirst+1;

//3、终止条件:如果只剩两个,则直接比较大小
    if(n ==2)
    {
        if(*pFirst>*pEnd)
            swap(pFirst,pEnd);

    }else
    {
     //4、获取最左边、最后边、还有中间位置指针
        int* pMid=pFirst+n/2;
        int* pLeft=pFirst;
        int* pRight=pEnd;

        while(pLeft<pRight)
        {
          //5、找到不小于分界数的位置 ,此处pLeft最多会到pMid处
            while(*pLeft<*pMid && pLeft<pMid)
                ++pLeft;
          //6、找到小于分界数的位置 ,此处pRight最多会到pMid处
            while(*pRight>=*pMid && pRight>pMid)
                --pRight;
                //7、因为后面递归会把分界值放在右侧,所以如果此处pLeft已经到了pMid处则不需要交换
            if(pLeft<pMid )
                swap(pLeft,pRight);
			//8、此处pLeft可能到达pMid+1处,pRight可能到达pMid-1处
            ++pLeft;
            --pRight;
        }
        //9、左侧递归(不包含分界值)
        SortByQuick(pFirst,pMid-1);
        //10、右侧递归(包含分界值)
        SortByQuick(pMid,pEnd);

    }
    return true;
}

5、归并法
归并可理解为先两两排序,然后四个一组排序,然后八个、、依次类推,代码如下:

bool SortByMerge(int* pFirst,int* pEnd)
{
    //1、参数合法性检查(包含终止条件 ,如果只剩一个元素 则不继续)
    if(pFirst == NULL || pEnd ==NULL || pEnd-pFirst<=0)
        return false;
 //2、获取个数
    const int n=pEnd-pFirst+1;

 //3、终止条件:如果只剩两个,则直接比较大小
    if(n ==2)
    {
        if(*pFirst>*pEnd)
            swap(pFirst,pEnd);

    }else
    {
     //4、获取分界点 分为两份
        int* pMid=pFirst+n/2;
         //5、先排左侧
        SortByMerge(pFirst,pMid);
             //6、再排右侧
        SortByMerge(pMid+1,pEnd);


             //7、此时 左侧是一串从小到大的有序数据 ,右侧同样
        int* pTmpLeft=pFirst;
        int* pTmpRight=pMid+1;

//8、在堆上分配空间
        int* nTmp= new int[n];
        int* pStart=nTmp;
        //9、移动数据到分配的空间
        while(pTmpLeft<=pMid && pTmpRight <=pEnd)
        {
         //10、如果左边的小,就先放左边到分配的空间
            if(*pTmpLeft<*pTmpRight)
            {
                *nTmp++=*pTmpLeft;
                ++pTmpLeft;
            }
            //11、如果右边的小,就放右边到分配的空间
            else if(*pTmpLeft>*pTmpRight)
            {
                *nTmp++=*pTmpRight;
                ++pTmpRight;
            }else
            {
            //12、如果相等,则左右都放
                *nTmp++=*pTmpLeft;
                ++pTmpLeft;
                *nTmp++=*pTmpRight;
                ++pTmpRight;
            }
        }
 //13、最后总有一个先满足终止条件,所以以下两个while只会执行其中一个 ,
        while(pTmpLeft<=pMid)
        {
            *nTmp++=*pTmpLeft++;
        }

        while(pTmpRight<=pEnd)
        {
            *nTmp++=*pTmpRight++;
        }
//14、拷贝数据
        for(int i=0;i<n;++i)
            *pFirst++=pStart[i];
//15、
        delete[] nTmp;

    }
    return true;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值