本文介绍的是数组和单链表的快速排序。
首先介绍一下快速排序:
快速排序的思想是基于分治的。在待排序表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;
}
}
以上是对快速排序基于数组和链表的所有内容。