对快排的递归, 非递归, 和扩展的思考.

一. 对于快排的定义, 和理解文章的要求:

  要求:

      1>对基础的数据结构有一定的熟悉, 和相关的认识.

      2>对c++的基础的语法和STL容器有相关的了解.

  定义:

      快速排序(Quick Sort)的基本思想是: 通过一趟的排序将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部记录的关键字小, 则可以分别对这两部分记录继续进行排序, 已达到整个序列有序的目的(大话数据结构 程杰P417).

二. 代码分析,

  <1>递归中快排分析.

 

 1 #include<stdio.h>
 2 #include<iostream>
 3 #include<vector>
 4 using namespace std;
 5 /*
 6     交换两个vector<int>的两个内容的值:
 7 */
 8 void swap(vector<int> &array, int left, int right)
 9 {
10     int tmp      = array[left];
11     array[left]     = array[right];
12     array[right]     = tmp;
13 }
14 
15 /*
16     选取第一个值, 并把比起大的放到后面,
17 比起小的放到前面.
18 */
19 int patition(vector<int> &array, int left, int right)
20 {
21     int pos = array[left];//对比的位置, 上图的tmp
22     while(left < right)
23     {
24         //从后面找较小的放到前面:
25         while(left < right && pos <= array[right]) {right--;}
26         swap(array, left, right);
27         
28         //找前面找较大的放到后面:
29         while(left < right && array[left] <= pos){left++;}
30         swap(array, left, right);
31     }
32     return left;
33 }
34 
35 /*
36     快排函数, 并作为递归函数:
37 */
38 void Qsort(vector<int> &array, int left, int right)
39 {
40     if(left < right)
41     {    
42         //返回已经调整的位置:
43         int pos = patition(array, left, right);
44         Qsort(array, left, pos-1);
45         Qsort(array, pos+1, right);
46     }
47 }
48 
49 int main()
50 {
51     vector<int> array = {7, 5, 8, 2, 6, 4};
52     Qsort(array, 0, array.size()-1);
53     
54     for(auto i:array)
55     {
56         cout << i << " ";
57     }
58     cout << endl; 
59     return 0;
60 }

 

     _1测试结果如下:

      

      支持环境为 Linux下 g++ -std=c++11.

    _2分析Qsort(vector<int> &array, int left, int right)

        

              因为 left < right则进入条件中:

                   执行 int pos = patition(array, left, right);操作,

              

              patition作用:

               就是要先选取当中的一个关键字, 比如7, 然后在想尽办法将它放到一个位置, 使它左边的值

               都比它小, 右边的值都比它大.

               而pos成为了关键中枢(比左边都大, 比右边都小)

        

        好吧,到这里后,  一步一步来分析:

          

      行, 到这里我们进行了第一次patition结束, 再往下分析

          

  <2>将递归转化为非递归.

       _1思路,

          将递归转化为非递归, 如上所示, 递归中用到的数据为 pos right, left等作为判断条件

              如果递归的话, pos+1  <  right || pos-1 > left 条件

              递归退出时 pos == right || pos == right

          而将递归转化为非递归是, 借用stack和pait<int left, int right>来进行操作

       _2代码如下:

        

#include<iostream>
#include<stack>
#include<vector>
#include<utility>

using namespace std;
/*
    使用栈stack<pair>和pair<int, int>来
解决递归转化为非递归问题.
*/
/*
    同上:
*/
void swap(vector<int> &array, pair<int, int> &elem)
{
    int temp = array[elem.first];
    array[elem.first] = array[elem.second];
    array[elem.second] = temp; 
}
/*
    同上:
*/
int patition(vector<int> &array, pair<int, int> elem)
{
    int pos = array[elem.first];
    while(elem.first < elem.second)
    {
        while(elem.first < elem.second && array[elem.second] >= pos)
        {
            elem.second--;
        }
        swap(array, elem);
        while(elem.first < elem.second && array[elem.first] <= pos)
        {
            elem.first++;
        }
        swap(array, elem);
    }
    return elem.first;
}

/*
    使用stack<pait<int, int>>对其的控制,
*/
void Qsort(vector<int> &array)
{
    stack<pair<int, int>> st;
    pair<int, int> pa = make_pair(0, array.size()-1);
    st.push(pa);
    while(!st.empty())
    {
        pa = st.top();
        st.pop();
        int pos = patition(array, pa);
        if(pos != pa.first)
        {
            st.push(make_pair(pa.first, pos-1));
        }
        if(pos != pa.second)
        {
            st.push(make_pair(pos+1, pa.second));
        }
    }
}

int main()
{
    vector<int> array = {7, 5, 8, 2, 6, 4};
    Qsort(array);
    for(auto i: array)
    {
        cout << i << " ";
    }
    cout << endl;
}

     _4.测试结果.

      

     _5.运行环境如上.

     _6.理解如下:

        

  <3>是否可以将单链表进行快排操作.

     _1思路理解:

        和前面的类似,  但是如何找到它的迭代器前驱, ???

       来一次单链表的循环, 这个不是很高效, 但是是一种问题的解决思路.

     _2代码如下:

       

#include<string>
#include<forward_list>
#include<stack>
#include<utility>
#include<iostream>
#include<cstdio>
/*
    使用了单链表来完成快排.
*/
using namespace std;
/*
    使用了using 声明了myType类型为迭代器
*/
using myType = forward_list<int>::iterator ;
//同上
void swap(myType &first, myType &second)
{
    int tmp = *first;
    *first  = *second;
    *second = tmp;
}
/*
    通过一边循环来找到tmp的前驱的迭代器:
*/
myType getPtrFront(forward_list<int> &single, myType tmp)
{
    myType ptr = single.begin();
    for(myType p = ++(single.begin());\
    p != tmp; ++p, ++ptr){}
    return ptr;
}
/*
    比前一个更加优化, 来找到前驱迭代器:
*/
myType getPFront(pair<myType, myType> pa)
{
myType tmp
= pa.first++; while(pa.first != pa.second) { pa.first++; tmp++; } return tmp; } myType patition(forward_list<int> &single, pair<myType, myType> pa) {
   myType tmp
= pa.first; while(pa.first != pa.second) { while(pa.first != pa.second && *(pa.second) >= *tmp) { pa.second = getPFront(pa); } swap(tmp, pa.second); tmp = pa.second;//对其迭代器tmp的维护 while(pa.first != pa.second && *tmp >= *(pa.first)) { pa.first++; } swap(tmp, pa.first); tmp = pa.first; } return tmp; } void Qsort(forward_list<int> &single) { pair<myType, myType> pa(single.begin(), getPtrFront(single, single.end())); stack<pair<myType, myType>> st; st.push(pa); while(!st.empty()) { pa = st.top(); st.pop(); myType tmp = patition(single, pa); if(pa.first != tmp) { st.push(make_pair(pa.first, getPtrFront(single, tmp))); } if(pa.second != tmp) { st.push(make_pair(++tmp, pa.second)); } } } int main() { forward_list<int> single_list = {7, 5, 8, 2, 6, 4}; Qsort(single_list); for(auto i : single_list) { cout << i << " "; } cout << endl; return 0; }

    _3测试如下:

      

    _4情景分析:

      其主要来找到其的前驱迭代器,  来完成后上述过程, 思路类似.

   <4>是否可以通过快排来对双链表进行操作.

      _1.和其上类似, 

      _2.代码如下:

        

#include<cstdio>
#include<string>
#include<list>
#include<stack>
#include<utility>
#include<iostream>
#include<vector>
using namespace std;
using myType = list<int>::iterator ;

void swap(myType &first, myType &second)
{
    int tmp = *first;
    *first  = *second;
    *second = tmp;
}

myType patition(list<int> &dlist, pair<myType, myType> pa)
{
    myType tmp = pa.first;
    while(pa.first != pa.second)
    {
        while(pa.first != pa.second && *(pa.second) >= *tmp)
        {
            --(pa.second);
        }
        swap(tmp, pa.second);
        tmp = pa.second;
        while(pa.first != pa.second && *tmp >= *(pa.first))
        {
            ++(pa.first);
        }
        swap(tmp, pa.first);
        tmp = pa.first;
    }
    return tmp;
}

void Qsort(list<int> &dlist)
{
    pair<myType, myType> pa(dlist.begin(), --dlist.end());
    stack<pair<myType, myType>> st;
    st.push(pa);
    while(!st.empty())
    {
        pa = st.top();
        st.pop();
        myType tmp = patition(dlist, pa);
        if(pa.first != tmp)
        {
            myType t = --tmp;
            st.push(make_pair(pa.first, t));
            tmp++;
        }
        if(pa.second != tmp)
        {
            myType t = ++tmp;
            st.push(make_pair(t, pa.second));
            tmp--;
        }
    }
}

int main()
{
    vector<int> array = {7, 5, 8, 2, 6, 4, 3, 10, 0};
    list<int> d_list(array.begin(), array.end());
    Qsort(d_list);
    for(auto i : d_list)
    {
        cout << i << " ";
    }
    cout << endl;
    return 0;
}

 

    _3.思路分析

      在其中主要是传进去的是迭代器, 对其进行操作. 思路类似.

  <5>. 效率分析.

      快排的时间复杂度取决于快排的深度, 类似于递归树, 

       最优的情况下:

            一分为二, 一个平衡的二叉树

         则:

          T(n) = 2T(n/2) + n;

         则:

          T(n)  <= O(nlogn);

        最坏情况下:

          它是一个斜树, O(n^2)

四.总结:

  本文章主要对快排进行了解, 和分析, 并对其进行了扩展。并参考了 大话数据结构, 数据结构(严蔚敏2th)等.

如有任何问题.请拍砖.

    

        

 

  

  

 

posted @ 2018-01-31 20:54  Top-jia  阅读(493)  评论(0)    收藏  举报