交换排序:通过依次交换逆序的元素使其有序化的过程。
介绍两种交换排序: 冒泡排序,快速排序
冒泡法:从第一个元素开始,依次比较相邻的两个元素,如果逆序则交换,第一趟比较结束后,序列中最大的元素将移动到序列末尾,即第n个位置,第二趟将次大元素移动到n-1位置…… 多趟比较后,会形成有序序列,排序方法类似气泡慢慢向上浮动,因此成为冒泡法。
快速排序: 对冒泡的改进,将序列中的关键字和指定元素(枢轴)比较,将序列以枢轴划分,保证枢轴大于其左边所有数,小于其右边所有数。
(枢轴的选取很关键,避免快排在局部有序数列中退化,再次使用的三者取中法)
按照以上方法,对上次划分的子序列进行递归划分,知道每个子序列只剩下一个元素不能划分为止,此时序列有序。
代码实现:
#include<iostream>
#define SIZE 21
typedef int Sqlist[SIZE];
using namespace std;
void swap(int &a, int &b)
{
a = a^b;
b = a^b;
a = a^b;
}
//==================================BubbleSort()==================================
/// @brief <对函数进行概括说明> 冒泡排序
///
/// <对函数进行详细说明> 内部排序,稳定排序,交换排序 时间复杂度:平均 O(n),最坏O(n^2)
///
/// @param [in, out] sq <参数说明,[in, out]表示参数的传递方向,需要根据情况进行选择> 数组
/// @param [in, out] n <参数说明,[in, out]表示参数的传递方向,需要根据情况进行选择> 数组大小
///
/// @return <返回值说明,可以配合使用DocGenList或DocGenTable> 无返回值
///
/// @remark <函数特别说明> 使用引用
///
/// @code
/// <在此添加示例代码>
/// @endcode
void BubbleSort(Sqlist &sq, int n)
{
cout << "冒泡排序:" << endl;
for (int i = 0; i < n - 1; ++i)
{
for (int j = 0; j < n - i - 1; ++j)
{
if (sq[j] > sq[j + 1])
{
swap(sq[j],sq[j+1]);
}
}
}
}
/
//================================PivotkeySelect()================================
/// @brief <对函数进行概括说明> 枢轴选取
///
/// <对函数进行详细说明> 三者取中
///
//================================================================================
int PivotkeySelect(Sqlist &sq, int low, int high)
{
int mid = low + ((high - low) >> 1);//计算数组中间的元素的下标
//使用三数取中法选择枢轴
if (sq[mid] > sq[high])//目标: sq[mid] <= sq[high]
{
swap(sq[mid], sq[high]);
}
if (sq[low] > sq[high])//目标: sq[low] <= sq[high]
{
swap(sq[low], sq[high]);
}
if (sq[mid] > sq[low]) //目标: sq[low] >= sq[mid]
{
swap(sq[mid], sq[low]);
}
//此时,sq[mid] <= sq[low] <= sq[high]
return sq[low];
//low的位置上保存这三个位置中间的值
//分割时可以直接使用low位置的元素作为枢轴,而不用改变分割函数了
}
//==================================Partition()=================================
/// @brief <对函数进行概括说明> 划分
///
/// <对函数进行详细说明> 用枢轴将数组划分
///
/// @sa <可以参考的类或函数,用空格分隔,函数名称后必须加()> PivotkeySelect()
//================================================================================
int Partition(Sqlist &sq, int low, int high)
{
int key = PivotkeySelect(sq,low,high); //辅助空间
while (low < high)
{
while (low < high && sq[high] >= key)
{
high--;
}
sq[low] = sq[high];
while (low < high && sq[low] <= key)
{
low++;
}
sq[high] = sq[low];
}
sq[low] = key;
return low;
}
//==================================QuickSort()=================================
/// @brief <对函数进行概括说明> 快速排序 对冒泡的改进 不稳定
///
/// <对函数进行详细说明> 将关键字与指定元素比较 递归 时间复杂度:平均O(nlog2^n) 最坏O(n^2)
///
/// @param [in, out] sq <参数说明,[in, out]表示参数的传递方向,需要根据情况进行选择> 数组
/// @param [in, out] low <参数说明,[in, out]表示参数的传递方向,需要根据情况进行选择> 最小下标
/// @param [in, out] high <参数说明,[in, out]表示参数的传递方向,需要根据情况进行选择> 最大下标
///
/// @return <返回值说明,可以配合使用DocGenList或DocGenTable> 返回low
///
/// @remark <函数特别说明>
///
/// @code
/// <在此添加示例代码>
/// @endcode
///
/// @sa <可以参考的类或函数,用空格分隔,函数名称后必须加()> Partition() PivotkeySelect()
//================================================================================
void QuickSort(Sqlist &sq, int low, int high)
{
if (low < high)
{
int prvitloc = Partition(sq, low, high); //将数组一分为二
QuickSort(sq, low, prvitloc - 1); //左半部分排序
QuickSort(sq, prvitloc + 1, high);
}
}
选择排序:
对于n个元素的序列,第一趟经n-1此比较,选出最小的放在第一个位置,第二趟从n-1个元素中,经过n-2次比较,选出最小的放在第二个位置……直到没有待比较的元素。
代码实现:
//====================================MinKey()====================================
/// @brief <对函数进行概括说明> 最小值选取
///
/// <对函数进行详细说明> 从key位置开始,找出大小为n数组中的最小值,并返回下标
///
/// @param [in, out] sq <参数说明,[in, out]表示参数的传递方向,需要根据情况进行选择>
/// @param [in, out] n <参数说明,[in, out]表示参数的传递方向,需要根据情况进行选择>
/// @param [in, out] key <参数说明,[in, out]表示参数的传递方向,需要根据情况进行选择>
///
//================================================================================
int MinKey(Sqlist &sq, int n, int key)
{
int k = key + 1;
for (; k < n; ++k)
{
if (sq[k] < sq[key]) //若小于则记录下标
{
key = k;
}
}
return key;
}
//==================================SelectSort()==================================
/// @brief <对函数进行概括说明> 简单选择排序
///
/// <对函数进行详细说明> n个元素,第一次n-1次比较,选出n个中最小元素,放在序列最前面
///
/// @param [in, out] sq <参数说明,[in, out]表示参数的传递方向,需要根据情况进行选择>
/// @param [in, out] n <参数说明,[in, out]表示参数的传递方向,需要根据情况进行选择>
///
/// @return <返回值说明,可以配合使用DocGenList或DocGenTable>
///
/// @remark <函数特别说明>
///
/// @code
/// <在此添加示例代码>
/// @endcode
///
/// @sa <可以参考的类或函数,用空格分隔,函数名称后必须加()> MinKey() swap()
//================================================================================
void SelectSort(Sqlist &sq, int n)
{
for (int i = 0; i < n - 1; ++i)
{
int j = MinKey(sq, n, i);
if (i != j)
swap(sq[i],sq[j]);
}
}
测试程序:
void main(void)
{
Sqlist sq = { 49, 38, 65, 97, 76, 13, 27, 49 };
Sqlist sq2 = { 49, 38, 65, 97, 76, 13, 27, 49 };
Sqlist sq3 = { 49, 38, 65, 97, 76, 13, 27, 49 };
cout << "原数组为:" << endl;
for (int i = 0; i < 8; ++i)
{
cout << sq[i]<<" ";
}
cout << endl;
BubbleSort(sq,8);
for (int i = 0; i < 8; ++i)
{
cout << sq[i] << " ";
}
cout << endl;
/
cout << "原数组为:" << endl;
for (int i = 0; i < 8; ++i)
{
cout << sq2[i] << " ";
}
cout << endl;
QuickSort(sq2, 0, 7);
cout << "快速排序:" << endl;
for (int i = 0; i < 8; ++i)
{
cout << sq2[i] << " ";
}
cout << endl;
//
cout << "原数组为:" << endl;
for (int i = 0; i < 8; ++i)
{
cout << sq3[i] << " ";
}
cout << endl;
SelectSort(sq3, 8);
cout << "交换排序:" << endl;
for (int i = 0; i < 8; ++i)
{
cout << sq3[i] << " ";
}
cout << endl;
}