引言:
快速排序是排序算法中,因其优秀的时间复杂度被人们比较广泛使用。接下来我们就来看一下快速排序的递归算法及非递归算法实现,及快速排序的两个拓展,单向扫面的快速排序和单链表的快速排序。
一、普通快速排序(双向扫描)
1.快速排序算法模拟图
2.代码演示
2.1 递归法
#include<iostream>
#include<iomanip>
using namespace std;
template<typename T>
int partion(T* a, int left, int right)
{
int i = left;
int j = right;
T tmp = a[left];
while (i < j)
{
while (i<j && a[j]>tmp)
{
j--;
}
if (i < j)
{
a[i++] = a[j];
}
while (i<j && a[i]<tmp)
{
i++;
}
if (i < j)
{
a[j--] = a[i];
}
}
a[i] = tmp;
return i;
}
template<typename T>
void Quick_sort(T* a, int left, int right)
{
if (left >= right){
return;
}
else{
int pos = partion(a, left, right);
Quick_sort(a, left, pos - 1);
Quick_sort(a, pos + 1, right);
}
}
template<typename T>
void print(T* a,int len)
{
for (int i = 0; i < len; i++)
{
cout << setw(4) << a[i];
}
cout << endl;
}
int main()
{
int a[] = { 55, 41, 26, 53, 58, 97, 93 };
int len = sizeof(a) / sizeof(a[0]);
Quick_sort<int>(a, 0, len - 1);
print<int>(a, len);
char arr[] = "whjikacds";
int length = strlen(arr);
Quick_sort<char>(arr, 0, length - 1);
print<char>(arr, length);
}
以上代码运行结果:
2.2 非递归法
#include<iostream>
#include<iomanip>
#include<stack>
using namespace std;
template<typename T>
int Partition(T* a, int left, int right)
{
int i = left;
int j = right;
T tmp = a[left];
while (i < j)
{
while (i<j && a[j]>tmp)
{
j--;
}
if (i < j)
{
a[i++] = a[j];
}
while (i<j && a[i]<tmp)
{
i++;
}
if (i < j)
{
a[j--] = a[i];
}
}
a[i] = tmp;
return i;
}
template<typename T>
void NonRec_quickSort(T* a,int len)
{
if (len <= 1)
return;
stack<T> st;
int mid = Partition(a, 0, len - 1);
if (mid > 1){
st.push(0);
st.push(len - 1);
}
if (mid < len - 2){
st.push(mid + 1);
st.push(len - 1);
}
while (!st.empty())
{
int right = st.top();
st.pop();
int left = st.top();
st.pop();
mid = Partition(a, left, right);
if (left < mid - 1){
st.push(left);
st.push(mid - 1);
}
if (right > mid + 1){
st.push(mid+1);
st.push(right);
}
}
}
template<typename T>
void print(T* a,int len)
{
for (int i = 0; i < len; i++)
{
cout << setw(4) << a[i];
}
cout << endl;
}
int main()
{
int a[] = { 55, 41, 26, 53, 58, 97, 93 };
int len = sizeof(a) / sizeof(a[0]);
NonRec_quickSort(a, len);
print(a, len);
char arr[] = "whjikacds";
int length = strlen(arr);
NonRec_quickSort(a, length);
print<char>(arr, length);
}
以上代码运行结果:
二、单向快速排序
上述的快速排序算法可以从两边扫描,若现在添加限定条件,只能从一边进行扫描,那么该如何实现快速排序呢?
1.算法图解演示:
2.代码演示:
#include<iostream>
#include<iomanip>
#include<stack>
#include<algorithm>
using namespace std;
template<typename T>
int split(T* a, int left, int right)
{
int i = left; //i指向比较元素的期望位置
T x = a[i]; //将该数组第一个元素设置为比较元素
//从数组的第二个元素起开始遍历,若找到的元素大于比较元素,则跳过
for (int j = left + 1; j <= right; j++)
{ //若找到了小于比较元素的数,则将其与前面较大的数进行交换
if (a[j] <= x)
{
i++;
swap(a[i], a[j]);
}
}
swap(a[left], a[i]); //将比较元素交换到期望位置
return i;
}
template<typename T>
void Quick_sort(T* a, int left, int right)
{
if (left >= right){
return;
}
else{
int pos = split(a, left, right);
Quick_sort(a, left, pos - 1);
Quick_sort(a, pos + 1, right);
}
}
template<typename T>
void print(T* a, int len)
{
for (int i = 0; i < len; i++)
{
cout << setw(4) << a[i];
}
cout << endl;
}
int main()
{
int a[] = { 55, 41, 26, 53, 58, 97, 93 };
int len = sizeof(a) / sizeof(a[0]);
Quick_sort<int>(a, 0, len - 1);
print<int>(a, len);
char arr[] = "whjikacds";
int length = strlen(arr);
Quick_sort<char>(arr, 0, length - 1);
print<char>(arr, length);
}
以上代码的运行结果为:
三、单链表的快速排序
通过上述求解我们知道快速排序亦可以用在单向扫描,所以举一反三,我们如何对单链表进行快速排序呢?
其实和上述的单向扫描算法思想是一致的,只是表达上有些许区别
代码演示:
#include <iostream>
#include <algorithm>
#include <iomanip>
using namespace std;
//构造结点并初始化
typedef struct node
{
int val;
node * next;
node(int x) :val(x), next(NULL){}
}mynode, *pmynode;
void swap(int* a, int * b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
//定位
node *partion(node *pbegin, node * pend)
{
if (pbegin == pend || pbegin->next == pend)
return pbegin;
int mykey = pbegin->val; //选择基准
node* p = pbegin;
node* q = pbegin->next;
while (q != pend)
{
if (q->val< mykey)
{
p = p->next;
swap(&p->val, &q->val); //小于则交换
}
q = q->next;//否则一直往下走
}
swap(&p->val, &pbegin->val); //定位
return p;
}
void quick_sort(node *pbegin, node *pend)
{
if (pbegin == pend || pbegin->next == pend)
return;
node *mid = partion(pbegin, pend);
quick_sort(pbegin, mid);
quick_sort(mid->next, pend);
}
node *mysort(node *head, node *end)
{
quick_sort(head, end);
return head;
}
int main()
{
node a(1);
node b(4);
node c(2);
node d(2);
node e(5);
node f(7);
a.next = &b;
b.next = &c;
c.next = &d;
d.next = &e;
e.next = &f;
pmynode head = &a;
//printf("%d", &a->val);
//如果节点的指针不为空则打印节点
while (head)
{
cout << setw(4) << head->val;
head = head->next;
}
cout << endl;
pmynode head0 = mysort(&a, &f);
while (head0)
{
cout << setw(4) << head0->val;
head0 = head0->next;
}
cout << endl;
return 0;
}
以上代码运行结果为:
四、快速排序的优化
我们知道快速排序越无序排序越快,当给定一个有序的数组进行排序的时候,它的时间复杂度仍为O(n),那么我们如何对快速排序进行优化,使其在各种情况下都是优秀的排序?
优化一:三位取中法
#include<iostream>
#include<iomanip>
#include<stack>
#include<algorithm>
using namespace std;
template<typename T>
int swap(T* a, T* b)
{
T tmp = a;
*a = *b;
*b = T;
}
int Partition(int* a, int left, int right)
{
int m = left + (right - left) / 2;
if (a[left] > a[right])
{
swap(a[left], a[right]);
}
if (a[m] > a[right])
{
swap(a[m], a[right]);
}
if (a[m] > a[left])
{
swap(a[m], a[right]);
}
int i = left;
int j = right;
int tmp = a[left];
while (i < j)
{
while (i<j && a[j]>tmp)
{
j--;
}
if (i < j)
{
a[i++] = a[j];
}
while (i<j && a[i]<tmp)
{
i++;
}
if (i < j)
{
a[j--] = a[i];
}
}
a[i] = tmp;
return i;
}
template<typename T>
void Quick_sort(T* a, int left, int right)
{
if (left >= right){
return;
}
else{
int pos = Partition(a, left, right);
Quick_sort(a, left, pos - 1);
Quick_sort(a, pos + 1, right);
}
}
template<typename T>
void print(T* a, int len)
{
for (int i = 0; i < len; i++)
{
cout << setw(4) << a[i];
}
cout << endl;
}
int main()
{
int a[] = { 55, 41, 26, 53, 58, 97, 93 };
int len = sizeof(a) / sizeof(a[0]);
Quick_sort<int>(a, 0, len - 1);
print<int>(a, len);
}
优化二:随机化
#include<math.h>
template<typename T>
int swap(T* a, T* b)
{
T tmp = a;
*a = *b;
*b = T;
}
int Partition(int* a, int left, int right)
{
swap(a[left], a[(int)(rand() % (right - left + 1)) + left]);
int i = left;
int j = right;
int tmp = a[left];
while (i < j)
{
while (i<j && a[j]>tmp)
{
j--;
}
if (i < j)
{
a[i++] = a[j];
}
while (i<j && a[i]<tmp)
{
i++;
}
if (i < j)
{
a[j--] = a[i];
}
}
a[i] = tmp;
return i;
}
template<typename T>
void Quick_sort(T* a, int left, int right)
{
if (left >= right){
return;
}
else{
int pos = Partition(a, left, right);
Quick_sort(a, left, pos - 1);
Quick_sort(a, pos + 1, right);
}
}
template<typename T>
void print(T* a, int len)
{
for (int i = 0; i < len; i++)
{
cout << setw(4) << a[i];
}
cout << endl;
}
int main()
{
int a[] = { 55, 41, 26, 53, 58, 97, 93 };
int len = sizeof(a) / sizeof(a[0]);
Quick_sort<int>(a, 0, len - 1);
print<int>(a, len);
}