【算法】快速排序及其拓展优化(单向快速排序、单链表的快速排序)

引言:

快速排序是排序算法中,因其优秀的时间复杂度被人们比较广泛使用。接下来我们就来看一下快速排序的递归算法及非递归算法实现,及快速排序的两个拓展,单向扫面的快速排序和单链表的快速排序。


一、普通快速排序(双向扫描)

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);

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值