链表的快速排序

来源:互联网 发布:三维软件是什么 编辑:程序博客网 时间:2024/06/05 19:52

首先,回忆一下数组的快排步骤:

函数参数: 数组arr, 起点nLow, 终点nHigh
功能: 把nLow 至 nHigh 段的数组进行一次快排。
结果:【比nMark小的元素】nMark【比nMark大的元素】

#区间分割法        1. 取最后一个元素为标记,用nSmall标记小区间大小,i 用来遍历数组;        2. 遍历值小于标记值:小区间的下一个不是当前位置,需要交换,否则直接小区间位置+1        3. 如此循环到  标记位置(最后一个元素)        4. 将标记元素(即最后一个元素)放到 s+1 的位置;

数组快排的链接: 快速排序(不稳定)挖坑填补法+区间分割法+3种优化方法

由此,我们写一下链表的步骤:
函数参数: List*pBegin,List*pEnd

1. 取第一个元素作为标记元素, 用pSmall指针,指向首元素;2. 使用pTemp遍历链表, 找到找到小于标记的元素,将pSmall移到下一位置;   若下一个位置不是当前位置, 将pSmall 和 pTemp 的元素进行交换;3. 重复 2, 直到pTemp == pEnd;4. 此时pSmall 指向小链表的最后一个元素, 将这个元素和标记元素(链表头)进行交换;5. 分别递归前半部分和后半部分;

先上代码,再分析:

//链表的快排void QuickSort2(List* pBegin, List* pEnd){    if (pBegin == NULL)        return;    if (pBegin == pEnd)        return;    int nTemp;    //1. 取第一个元素作为标记元素, 用pSmall指针,指向首元素;     int nMark = pBegin->nvalue;    List* pSmall = pBegin;    //2. 使用pTemp遍历链表    List* pTemp = pBegin->pNext;      while (pTemp != pEnd)    {        //2.1 找到找到小于标记的元素,将pSmall移到下一位置;        if (pTemp->nvalue < nMark)        {            pSmall = pSmall->pNext;            //2.2 若下一个位置不是当前位置, 将pSmall 和 pTemp 的元素进行交换;            if (pSmall != pTemp)            {                nTemp = pTemp->nvalue;                pTemp->nvalue = pSmall->nvalue;                pSmall->nvalue = nTemp;            }        }        pTemp = pTemp->pNext;    }    //把小链表的最后一个元素和头(标记)交换    //这样pSmall 前就是比nMark小的,后就是比nMark大的;    //这块就是把: 16,9,5,15,8,23 --》 8,9,5,15,16,23;    nTemp = pSmall->nvalue;    pSmall->nvalue = pBegin->nvalue;    pBegin->nvalue = nTemp;    //while 循环判断,刚好不需要判断最后一个元素,因此就把pSmall 跳过了;    QuickSort2(pBegin, pSmall);     QuickSort2(pSmall->pNext, pEnd);}int main(){    int arr[] = {16,9,23,5,15,8};    Mylist list;    List* pList = list.CreateaaList(arr, sizeof(arr) / 4);    list.Print(pList);    QuickSort2(pList, NULL);    list.Print(pList);    system("pause");    return 0;}

解释一下, 递归的参数问题:
在数组的快排中,我们是这样写的,先一次快排,将元素分成两部分, 前部分比标记小,后部分比标记大。返回标记位置,再对 标记的前后两部分进行排序;标记元素已经确定位置,不需要再参加排序了。

    int nStandard = Sort(arr, nLow, nHigh);    QuickSort(arr, nLow, nStandard -1);    QuickSort(arr, nStandard+1, nHigh);

在 链表的快排中, 循环判断条件是 pTemp != pEnd, 也就是pEnd 这一位没有进行判断是否加入小链表中。
在函数调用时,我们传入的参数是 QuickSort2(pList, NULL); 所以刚好pTemp是从头判断到尾。
进行递归的时候, 传入的pSmall 刚好就不被判断。完成“已经确定位置的标记元素,不需要再参加排序了。” 这一规则。

QuickSort2(pBegin, pSmall); QuickSort2(pSmall->pNext, pEnd);

在开始写的时候, 总想着需要记录pSmall 的前一个元素, 然后递归的时候传
头 — small 前一个, small 后一个—-尾;
这样看似没问题,但是总是跳过元素,然后程序就崩了, 就是没理解好这块。

原创粉丝点击