排序

排序是个经典话题,但很容易忘掉,记下来温故知新。实现算法不一定最优,主要体现思想。

排序在很多算法书上都有涉及,本人再网上参考结合一些资料,整理有如下几种:(c++实现,默认从小到大,从左至右,总个数nCount)

备注:其中涉及的ArrSwap(),ArrMax(),ArrMin()不再赘述

void Bubble(int* Numbers, int nCount);        //1.冒泡
void Select(int* Numbers, int nCount);        //2.选择
void Insert(int* Numbers, int nCount);        //3.插入
void ShellSort(int* Numbers, int nCount);    //4.希尔
void Heap(int* Numbers, int nCount);        //5.堆排
void Merge(int* Numbers, int nCount);        //6.归并
void Bucket(int* Numbers, int nCount);        //7.桶排
void Quick(int* Numbers, int nCount);        //8.快速
void Base(int* Numbers, int nCount);        //9.基数
void Count(int* Numbers, int nCount);        //10.计数
void Topology(int* Numbers, int nCount);    //11.拓扑
  1. 冒泡:从最左开始,左右比较,大的右调,到最后,最右边就是最大值。下次比较总数减1,如此往复总数为1时即算完成。code:
    void Bubble(int* Numbers, int nCount)
    {
        for (int i = 0; i < nCount - 1; ++i)
        {
            for (int j = 1; j < nCount - i; ++j)
            {
                if (Numbers[j] < Numbers[j - 1])
                    ArrSwap(Numbers, j, j+1);
            }
        }
    }

     

  2. 选择:从最左到最右,找到最小值,与最左对换值;最左右移1再重复直至最左与最右重合即算完成,code:
    void Select(int* Numbers, int nCount)
    {
        for (int i = 0; i < nCount - 1; ++i)
        {
            int nMin = i;
            for (int j = i + 1; j < nCount; ++j)
            {
                if (Numbers[j] < Numbers[nMin])
                    nMin = j;
            }
            ArrSwap(Numbers, nMin, i);
        }
    }

     

  3. 插入:假设a[1,n]是个有序序列,那么第n+1个插入合适位置使a[1,n+1]一样有序直至n+1=nCount;所谓合适即( a[cur-1] <= a[cur] <= a[cur+1] )code:
    void Insert(int* Numbers, int nCount)
    {
        for (int nLast = 1;  nLast < nCount; ++nLast)
        {
            for (int i = nLast; i > 0; --i )
                (Numbers[i] < Numbers[i - 1]) ?    ArrSwap(Numbers, i, i-1) : i = 0;
        }
    }

     

  4. 希尔:step=count/2;遍历时比较a[n],a[n+step]大数向右换(确保n+step < nCount),调整step=step/2再往复直到step=0时完毕(后续补图叙)。code:
    void ArrShell(int* Numbers, int nCount, int nStep)
    {
        if (nStep == 0)
            return;
        int nNewCount = nCount - nStep;
        for (int i = 0; i < nNewCount; ++i)
        {
            if (Numbers[i] > Numbers[i + nStep])
                ArrSwap(Numbers, i, i + nStep);
        }
        ArrShell(Numbers, nCount, nStep/2);
    }
    void ShellSort(int* Numbers, int nCount)
    {
        ArrShell(Numbers, nCount, nCount/2);
    }

     

  5. 堆排:按顺序填充完全二叉树,再调整使树LR<P,谓之堆。最尾换顶再削掉尾再调整成堆,如此往复被削掉的尾按次手机就是个有序序列(后续补图叙)。code:
    void AdjustHeap(int* Numbers, int nCount, int nAim)
    {
        int nLeft = nAim*2;
        int nRight = nLeft + 1;
        int nMax = (nLeft != nCount && Numbers[nLeft-1] < Numbers[nRight-1]) ? nRight : nLeft;
        if (Numbers[nMax-1]>Numbers[nAim-1])
        {
            ArrSwap(Numbers, nAim-1, nMax-1);
            if (nMax<=nCount/2)
                AdjustHeap(Numbers, nCount, nMax);
        }
    }
    void Heap(int* Numbers, int nCount)
    {
        do{
            for (int i = nCount/2; i >= 1; --i)
                AdjustHeap(Numbers, nCount, i);
            ArrSwap(Numbers, 0, --nCount);
        } while (nCount > 1);
    }

     

  6. 归并:将序列一分为二,再分为二,直到不能再分其就是一个有序序列,该序列只有一个数,然后合并有序序列组成更大的有序序列(后续补图叙)。code:

    void ArrMerge(int* LArr, int nL, int* RArr, int nR, int* AimArr, int nAim)
    {
        int nLi = 0, nRi = 0, nAi = 0;
        while (nLi < nL && nRi < nR)
            AimArr[nAi++] = (LArr[nLi] < RArr[nRi]) ? LArr[nLi++] : RArr[nRi++];    
        for (int i = nAi; i < nAim; ++i)
            AimArr[i] = (nLi == nL) ? RArr[nRi++] : LArr[nLi++];
    }
    void Merge(int* Numbers, int nCount)
    {
        if (1 == nCount)
            return;
        int nLeft = nCount/2;
        int nRight = nCount - nLeft;
        int* LArr = new int[nLeft];
        int* RArr = new int[nRight];
        for (int i = 0; i < nCount; i++)
            (i < nLeft) ? (LArr[i] = Numbers[i]) : (RArr[i-nLeft] = Numbers[i]);
        Merge(LArr, nLeft);
        Merge(RArr, nRight);
        ArrMerge(LArr, nLeft, RArr, nRight, Numbers, nCount);
        delete[] LArr;
        delete[] RArr;
    }

     

  7. 桶排:满分100分,10分1级共10级(10个桶),分越高级越高,不同分数装入相应桶,桶内排序,全部桶排完按桶次序收集即可(其中桶中的排序是可选的)。code:

    void Bucket(int* Numbers, int nCount)
    {
        int Max = Numbers[0];
        int Min = Numbers[0];
        for (int i = 0; i < nCount; i++)
        {
            if (Max < Numbers[i])
                Max = Numbers[i];
            if (Min > Numbers[i])
                Min = Numbers[i];
        }
        int nBuckets = 4;
        int nStep = (Max+1-Min)/4 + ((0 == (Max+1-Min) %4) ? 0 : 1);
        list<int>* Bucs = new list<int>[nBuckets];
        for (int i = 0; i < nCount; i++)
            Bucs[(Numbers[i] - Min)/nStep].push_back(Numbers[i]);
        for (int i = 0; i < nBuckets ; i++)
            Bucs[i].sort();
    
        int gIndex = 0;
        for (int i = 0; i < nBuckets ; i++)
        {
            for (list<int>::iterator it = Bucs[i].begin(); Bucs[i].end() != it; ++it)
                Numbers[gIndex++] = *it;
        }
        delete[] Bucs;
    }

     

  8. 快排:左大值右换,右小值左换,直到左==右,该数位置即定,其左右序列再如此往复则每个数都能找到自己的位置,使得L<=R。code:
    void ArrQuick(int* Numbers,int nPosL,int nPosR)
    {
        if(nPosL >= nPosR)
            return;
        int nL = nPosL;
        int nR = nPosR;
        int temp = Numbers[nPosL];
        while(nL != nR)
        {
            while(nL < nR && Numbers[nR] >= temp) 
                nR--;
            if(nR > nL)
                Numbers[nL] = Numbers[nR];
            while(nL < nR && Numbers[nL] <= temp)
                nL++;
            if(nL < nR)
                Numbers[nR] = Numbers[nL];
        }
        Numbers[nL] = temp;
        ArrQuick(Numbers,nPosL,nL-1);
        ArrQuick(Numbers,nL+1,nPosR);
    }
    void Quick(int* Numbers, int nCount)
    {
        ArrQuick(Numbers, 0, nCount-1);
    }

     

  9. 基数:有桶排的思想。比如正整数,把个位数由0-9分到相应桶,再按桶次收集。更高位也照次方法直到最高位,最后收集的即为目标序列。code:
    void Base(int* Numbers, int nCount)
    {
        int nMax = ArrMax(Numbers, nCount);
        int nLoop = 0;
        while (nMax > 0)
        {
            nLoop++;
            nMax = nMax/10;
        }
        for (int i = 0; i < nLoop; ++i)
        {
            list<int> allList[10];
            for (int j = 0; j < nCount; ++j)
            {
                int nMod = 1;
                for (int ii = 0; ii <= i; ii++)
                    nMod = nMod * 10;
                int nDiv = nMod / 10; 
                int nWhichList = (Numbers[j] % nMod / nDiv);
                allList[nWhichList].push_back(Numbers[j]);
            }        
            int nArrIndex = 0;
            for (int k = 0; k < 10; ++k)
            {
                for (list<int>::iterator it = allList[k].begin(); allList[k].end() != it; ++it)
                    Numbers[nArrIndex++] = *it;
            }
        }
    }

     

  10. 计数:如序列值[0-9],则生成cnt序列,记录值的个数,再将其转为由左至右cnt值的累加值,序列写入cnt对应偏移位置即可。code:
    void ArrCount(int* Numbers, int nCount, int nMax)
     {
         int* Couter = new int[nMax+1];
         for (int i = 0; i< nMax+1; ++i)
             Couter[i] = 0;
         for (int i = 0; i <nCount; ++i)
             (Couter[Numbers[i]])++;
         for (int i = 1; i< nMax+1; ++i)
             Couter[i] = Couter[i] + Couter[i -1];
         int* Temp = new int[nCount];
         for (int i = 0; i < nCount; ++i)
         {
             Temp[Couter[Numbers[i]]-1] = Numbers[i];
             Couter[Numbers[i]]--;
         }
         for (int i = 0; i < nCount; ++i)
             Numbers[i] = Temp[i];
         delete[] Temp;
         delete[] Couter;
     }
     void Count(int* Numbers, int nCount)
     {
         int nMax = ArrMax(Numbers, nCount);
         ArrCount(Numbers, nCount, nMax);
     }

     

  11. 拓扑暂时还没有接触过,后续更新

 

posted @ 2014-08-06 00:28  l6  阅读(230)  评论(0编辑  收藏  举报