选择排序
思想
将排序序列中的某元素作为基本值,按照该基本值将排序组合分成两个子序列,
左子序列均小于基准值,右子序列均大于基准值,然后左右序列重复这个操作,
直到数组有序为止。
确定基本值
//根据左值,右值,中值判断哪个位置的值为第二大的数,返回这个位置,将其作为基本数
int RealKey(int* a, int begin, int end)
{
int mid = begin + ((end - begin) >> 1);
if (a[mid] > a[begin])
{
if (a[begin] > a[end])
return begin;
else if (a[end] > a[mid])
return mid;
}
if (a[mid] > a[end])
{
if (a[begin] > a[mid])
{
return mid;
}
else if (a[end] > a[begin])
{
return end;
}
}
return begin;
}
常见的方法有:
1.交换法
int FastBuild1(int* a, int begin, int end)
{
int key = RealKey(a, begin, end);
swap(a[key], a[begin]);//将基本值和第一个数交换
while (begin < end)
{
while (begin < end && a[end] > a[key])
{
end--;
}
while (begin < end && a[begin] <= a[key])//因为第一个数就是基本值,所以在a[begin] = a[key]的时候要begin++
{
begin++;
}
swap(a[begin], a[end]);//找到左边比基本值小的数和右边比基本值大的数,将其交换
}
swap(a[key], a[begin]);//跳出循环的时候,将第一个数和最后begin出现的位置进行交换
return begin;
}
2.挖空法
int FastBuild2(int* a, int begin, int end)
{
int key = RealKey(a, begin, end);
int newkey = a[key];
swap(a[begin], a[key]);//将基本值和第一个数交换
while (begin < end)
{
while (begin < end && a[end] > newkey)
{
end--;
}
a[begin] = a[end];//将右边比基础值大的数给左边下标为begin的数
while (begin < end && a[begin] <= newkey)
{
begin++;
}
a[end] = a[begin];//将左边比基础值小的数给右边下标为end的数
}
a[begin] = newkey;//最后下标为begin的位置空缺,将先前的临时值交换
return begin;
}
3.双指针法
int FastBuild3(int* a, int begin, int end)
{
int cur = begin + 1;
int pur = begin;
int sad = begin;
while (cur <= end)
{
if (a[sad] > a[cur] && ++pur != cur)//注意&&是两个为真才为真,前后的判断语句是要执行的。
{
swap(a[pur], a[cur]);
}
cur++;
}
swap(a[sad], a[pur]);//最后交换sad下标和pur下标对应的数
return pur;
}
递归写法
void QuickSort1(int*a, int begin, int end)
{
if (begin >= end)
return;
int div = QuickBuilt3(a, begin, end);
QuickSort1(a, begin, div-1);
QuickSort1(a, div + 1, end);
}
非递归写法
非递归排序需要栈辅助,控制每次的FastBuild的范围。
void FastSort(int* a, int begin, int end)
{
stack<int> s;
s.push(end);
s.push(begin);
while (!s.empty())//判断条件为堆不为空
{
int left = s.top();
s.pop();
int right = s.top();
s.pop();
int div = FastBuild(a, left, right);//给定左右范围后,进行一次快速排序
if (div - 1 > left)//构造左部分
{
s.push(div - 1);
s.push(left);
}
if (div + 1 < right)//构造右部分
{
s.push(right);
s.push(div + 1);
}
}
}
代码样例:
int main()
{
int a[] = { 49, 38, 65, 97, 76, 13, 27, 49 };
int n = sizeof(a) / sizeof(a[0]);
int begin = 0;
int end = n - 1;
FastSort(a, begin, end);
for (auto e : a)
{
cout << e << " ";
}
system("pause");
return 0;
}
代码执行:
快速排序特点:
1.综合性能较好
2.时间复杂度O(n*logn)
3.空间复杂度O(logn)
4.稳定性:不稳定