递归版本的实现
方法一:填坑法
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);
}
}
}