算法学习-快速排序

递归版本的实现

方法一:填坑法

1.利用分化函数求第一个基准元素
2.递归调用快排
主要是分化函数partition的实现
分化函数步骤:
1.第一个位置作为基准,位置为初始坑
2.先从右边元素,找到小于基准的元素,填入坑中,更新坑位置,找到后转3
3.从左边找到大于基准的元素,填入坑中,更新坑位置;2,3循环直到left = right
4.最后的坑填入基准元素。

方法二:指针交换法

与填坑法相比,只有分化函数不同,分化函数中的元素交换次数少,更简单
交换思想:左边大于基准的元素和右边小于基准的元素交换
分化函数步骤:
1.交换
2.当left和right指针重合之时,交换pivot元素和left与right重合点的元素

代码:

填坑法
 

#include <iostream>
using namespace std;

template<typename T> 
int length(T& arr)
{
	return sizeof(arr) / sizeof(arr[0]);
}
void quickSort(int arr[], int startIndex, int endIndex);
int partition(int arr[], int startIndex, int endIndex);
int main()
{
	int arr[12] = { 4,7,6,5,3,2,8,1,10,0,10,7 };
	quickSort(arr, 0, length(arr) - 1);
	for (int i = 0; i < length(arr);  i++)
		cout << arr[i] << " ";
	cout << endl;
	system("pause");
	return 0;
}

void quickSort(int arr[], int startIndex, int endIndex)
{
	if (startIndex < endIndex)
	{
		int pivot = partition(arr, startIndex, endIndex);
		quickSort(arr, startIndex, pivot);
		quickSort(arr, pivot + 1, endIndex);
	}

}
//填坑法
int partition(int arr[], int startIndex, int endIndex)
{
	int pivot = arr[startIndex];//第一个位置作为基准
	int left = startIndex;
	int right = endIndex;
	//坑的位置
	int index = startIndex;
	while (left < right)//大循环
	{
		while (right > left)//先从右向左
		{
			if (arr[right] < pivot)//小于基准,交换
			{
				arr[left] = arr[right];//填坑
				index = right;//更新坑位置
				left++;
				break;//跳出右边的小循环
			}
			right--;
		}
		while (left < right)//左到右
		{
			if (arr[left] > pivot)
			{
				arr[right] = arr[left];
				index = left;
				right--;
				break;
			}
			left++;
		}
	}
        arr[index] = pivot;
	return index;
}

指针交换法
 

//指针交换法:左边大于基准的元素和右边小于基准的元素交换
int partition(int arr[], int startIndex, int endIndex)
{
	int pivot = arr[startIndex];
	int left = startIndex;
	int right = endIndex;
	while (left != right)
	{
		while (right > left && arr[right] >= pivot)
			right--;
		while (right > left && arr[left] <= pivot)
			left++;
		//交换
		int tmp = arr[right];
		arr[right] = arr[left];
		arr[left] = tmp;
	}
	//当left和right指针重合之时,交换pivot元素和left与right重合点的元素
	int p = arr[left];
	arr[left] = arr[startIndex];
	arr[startIndex] = p;
	return left;
}

非递归实现

和刚才的递归实现相比,代码的变动仅仅在quickSort方法当中,partition函数可以用填坑法或者指针交换法。该方法中引入了一个存储Map类型元素的栈,用于存储每一次交换时的起始下标和结束下标。
用栈的方式,代码中一层一层的方法调用,本身就是一个函数栈。
每次进入一个新方法,就相当于入栈;每次有方法返回,就相当于出栈。
所以,我们可以把原本的递归实现转化成一个栈的实现,在栈当中存储每一次方法调用的参数:

 

//非递归实现
//用栈的方式,代码中一层一层的方法调用,本身就是一个函数栈。
//每次进入一个新方法,就相当于入栈;每次有方法返回,就相当于出栈。
void quickSort(int arr[], int startIndex, int endIndex)
{
	// 用一个集合栈来代替递归的函数栈
	stack<map<string, int>> quickSortStack;
	//数组的起止下标,以哈希的形式入栈
	map<string, int> rootParam;
	rootParam.insert(pair<string, int>("startIndex", startIndex));//利用insert插入pair类型的数据
	rootParam.insert(pair<string, int>("endIndex", endIndex));
	quickSortStack.push(rootParam);
	//循环结束条件:栈为空时结束
	while (!quickSortStack.empty())
	{
		map<string, int> param = quickSortStack.top();//获取栈顶:入栈是先左后右,所以出栈先右后左
		quickSortStack.pop();//栈顶出栈
		//int pivotIndex = partition(arr, param["startIndex"], param["endIndex"]);//利用map[key]获取键对应的值,不好,如果查找不到会插入
		int pivotIndex = partition(arr, param.find("startIndex")->second, param.find("endIndex")->second);//利用find返回的迭代器
		//根据基准元素分为两部分,把每一部分起止下标入栈
		if (param.find("startIndex")->second < pivotIndex - 1)
		{
			map<string, int> leftParam;
			leftParam.insert(pair<string, int>("startIndex", param.find("startIndex")->second));
			leftParam.insert(pair<string, int>("endIndex", pivotIndex - 1));
			quickSortStack.push(leftParam);
		}
		if (pivotIndex + 1 < param.find("endIndex")->second)
		{
			map<string, int> rightParam;
			rightParam.insert(pair<string, int>("startIndex", pivotIndex + 1));
			rightParam.insert(pair<string, int>("endIndex", param.find("endIndex")->second));
			quickSortStack.push(rightParam);
		}

	}
}

猜你喜欢

转载自blog.csdn.net/vict_wang/article/details/83118746
今日推荐