快速排序(数组和链表)

本文介绍的是数组和单链表的快速排序。

首先介绍一下快速排序:

快速排序的思想是基于分治的。在待排序表L[ 1,2…N ] 中任取一个元素作为基准 pivot ,通过一趟排序将待排序表划分为独立的两个部分 L[ 1,2…K-1 ] 和 L[ K+1…N ],

使得 L[ 1,2…K-1 ]  中所有元素的值都小于 pivot ,L[ K+1…N ] 中的所有元素都大于等于 pivot 的值,则 pivot 放在中间的 L[K] 的位置上,这个过程完成了一次快速排序。

然后分别对两个字表进行递归 ,重复上面两个动作,直到每个部分都只有一个元素或者为空为止,这就会使每个元素都放在了最终的位置。

效率分析:

空间:因为是递归完成的,所以需要借助一个递归栈来完成。当已经有序时,会进行 N-1 次递归,此时的递归层次最多,栈的深度为O(N)。但平均情况下,还是比较好的,

为O(LogN)。

时间:运行时间与划分是否对称有关系,所以中枢值得选择就是比较重要的了。可以参照STL中对于中枢值得选取。一般情况下,时间复杂度是O(NLogN)。

以下给出对于 数组 的快速排序算法:

 首先,声明了一个容器 Vector:

//  以下是对容器的声明
vector<int> v{10,4,9,12,7,6,18,1,25};

容器声明完成以后,就可以对其进行快速排序:

void QuickSort( vector<int> &v, int low, int high )
{
    //  满足递归的条件
    if ( low < high )
    {
        //  这里是对容器的划分的方法
        int key = Partition( v,low,high );
        //  依次对其左右两个区间进行快速排序操作
        QuickSort( v, low, key );
        QuickSort( v, key+1, high);
    }
}

下面给出划分的方法:

int Partition( vector<int> &v, int low, int high )
{
    //  获取中枢值
    int key = v[low];
    //  划分的主程序
    while( low < high )
    {
        while( v[high] > key && high > low )
            high--;
        v[low] = v[high];
        while( v[low] < key && low < high)
            low++;
        v[high] = v[low];
    }
    v[low] = key;

    return low;
}

对以上声明的容器调用快速排序和排序后的结果输出:

// 调用快速排序
QuickSort( v,0,v.size()-1 );
// 输出,通过调用仿函数实现
for_each( v.begin(),v.end(), print<span style="font-family: Arial, Helvetica, sans-serif;">() );</span>

以下给出仿函数的定义:

具体仿函数的使用,参照其他博客

class print
{
public:
    void operator()( const int i )
    {
        cout << i << " ";
    }
};

以上就是对数组的快速排序。

下面给出相对于链表的快速排序的算法:

先给出链表节点的定义:

struct Link
{
    int value;
    struct Link *next;
    Link():value(0),next(nullptr){}
    Link(int x):value(x),next(nullptr){}
};

typedef struct Link node;

以下给出快速排序的思想,具体解释见注释:

//  注意这里形参的声明方法,一定要加上 & 符号
//  仔细想想为什么
void QuickSort( node* &head , node* &end )
{
    // 声明四个节点,方便保存分开后的左右两个链表
    node *head1,*end1,*head2,*end2;
    head1 = end1 = head2 = end2 = nullptr;

    if ( head == nullptr )
        return;

    node *p,*pre1,*pre2;
    p = pre1 = pre2 = nullptr;

    // 取出一个节点作为中枢点
    int key = head->value;
    // 将头节点孤立出来
    p = head->next;
    head->next = nullptr;

    while( p != nullptr )
    {
        // 左
        if( p->value < key )
        {
            // 头结点为空的情形
            if ( head1 == nullptr )
            {
                head1 = p;
                pre1 = p;
            }
            else  // 头结点非空的情形
            {
                pre1->next = p;
                pre1 = p;
            }
            p = p->next;
            pre1->next = nullptr;
        }
        else
        {
            if ( head2 == nullptr )
            {
                head2 = p;
                pre2 = p;
            }
            else
            {
                pre2->next = p;
                pre2 = p;
            }
            p = p->next ;
            pre2->next = nullptr;
        }
    }
    // 给出尾节点
    end1 = pre1;
    end2 = pre2;

    // 分别对左右两个区间进行快速排序
    QuickSort(head1,end1);
    QuickSort(head2,end2);

    // 排序之后,链表的融合
    if ( head1 != nullptr && head2 != nullptr)
    {
        end1->next = head;
        head->next = head2;
        head = head1;
        end = end2;
    }
    else if ( head1 != nullptr )
    {
        end1->next = head;
        end = head;
        head = head1;

    }
    else if ( head2 != nullptr )
    {
        head->next = head2;
        end = end2;
    }
}

以上是对快速排序基于数组和链表的所有内容。

点赞