在最近的学习中,对于排序算法进行了一定的学习,在这里对快速排序和选择排序的部分内容进行说明,其余内容在后期会进行补充,感谢大家提出宝贵意见。
宏定义如下:
<span style="font-size:18px;"><strong><strong><span style="font-size:18px;">#include <iostream>
using namespace std;
#define M 21
typedef int SqList[M];</span></strong></strong></span>
一.冒泡排序
<span style="font-size:18px;"><strong><strong><span style="font-size:18px;">void BubbleSort(SqList &L,int n) //冒泡排序
{
for(int i = 0;i < n-1;++i) //外层循环记录循环次数
{
for(int j = 0;j < n-i-1;++j) //内层循环记录每一次循环比较的次数
{ //(j<n-i-1)比较一次后,其后值不参与再比较
if(L[j] > L[j+1]) //若前者大于后者,则交换位置
{
int tmp = L[j];
L[j] = L[j+1];
L[j+1] = tmp;
}
}
}
}</span></strong></strong></span>
二.快速排序
<span style="font-size:18px;"><strong><strong><span style="font-size:18px;">//改进方式,直接赋值
int Partition(SqList &L,int low,int high) //返回枢轴所在位置,它之前的小于它
{ //之后的大于它
int key = L[low]; //枢轴记录关键字
while(low < high) //判别条件,不满足时结束
{
while(low < high && L[high] >= key ) //若右边的大于枢轴
{
high--; //向前比较
}
L[low] = L[high]; //否则赋值
while(low < high && L[low] <= key) //若左边的小于枢轴
{
low++; //向后比较
}
L[high] = L[low]; //否则赋值
}
L[low] = key; //此时low = high,即可等价为L[high] = key,枢轴记录到位
return low; //返回此时位置
}
//交换方式
/*int Partition(SqList &L,int low,int high)
{
int key = L[low];
while(low < high)
{
while(low < high && L[high] >= key )
{
high--;
}
int tmp = L[low];
L[low] = L[high];
L[high] = tmp;
while(low < high && L[low] <= key)
{
low++;
}
tmp = L[low];
L[low] = L[high];
L[high] = tmp;
}
return low;
}*/
void QuickSort(SqList &L,int low,int high) //快速排序
{
if(low < high)
{
int prvitloc = Partition(L,low,high); //将数组一分为二
QuickSort(L,low,prvitloc-1); //左半部分排序
QuickSort(L,prvitloc+1,high); //右半部分排序
}
}</span></strong></strong></span>
对于快速排序有如下的优化方法:
1.L[low] L[high] L[(low+high)/2]从中找中间值作为枢值
实现代码如下:
//改进方法 L[low] L[high] L[(low+high)/2]从中找中间值作为枢值
int Index(int a,int b,int c) //查找作为枢值的值
{
if(a < b)
{
if(a < c)
{
if(b < c)
{
return b;
}
else
{
return c;
}
}
else
{
return a;
}
}
else //b <= a
{
if(c < a)
{
if(b < c)
{
return b;
}
else
{
return c;
}
}
else
{
return a;
}
}
}
int Partition(SqList &L,int low,int high) //返回枢轴所在位置,它之前的小于它
{ //之后的大于它
int key = Index(L[low],L[high],L[(low+high)/2]);
while(low < high) //判别条件,不满足时结束
{
while(low < high && L[high] >= key ) //若右边的大于枢轴
{
high--; //向前比较
}
int tmp = L[low]; //交换位置
L[low] = L[high];
L[high] = tmp;
while(low < high && L[low] < key) //若左边的小于枢轴
{
low++; //向后比较
}
tmp = L[low]; //交换位置
L[low] = L[high];
L[high] = tmp;
}
return low; //返回此时位置
}
测试代码与原方法相同。
2.改进方法 L[low] L[high] L[(low+high)/2]从中找中间值作为枢值且在指针high增1和low减1时同时进行冒泡操作,即在相邻两个纪录处于“逆序”时进行交换,同时算法中附设两个布尔型变量分别指示low和high在从两端向中间移动过程中是否进行交换记录的操作,若指针low在从低端向中间的移动过程中没有进行交换记录的操作,则不再需要对低端子表进行操作,同理高端子表类似。
实现代码如下:
//改进方法 L[low] L[high] L[(low+high)/2]从中找中间值作为枢值且在指针high增1和low减1时同时进行冒泡操作
//即在相邻两个纪录处于“逆序”时进行交换,同时算法中附设两个布尔型变量分别指示low和high在从两端向中间
//移动过程中是否进行交换记录的操作,若指针low在从低端向中间的移动过程中没有进行交换记录的操作,则不再
//需要对低端子表进行操作,同理高端子表类似
int Index(int a,int b,int c) //查找作为枢值的值
{
if(a < b)
{
if(a < c)
{
if(b < c)
{
return b;
}
else
{
return c;
}
}
else
{
return a;
}
}
else //b <= a
{
if(c < a)
{
if(b < c)
{
return b;
}
else
{
return c;
}
}
else
{
return a;
}
}
}
bool Right(SqList &L,int low,int high) //布尔型变量指示low从左向中间移动过程中是否进行交换记录的操作
{
int key = Index(L[low],L[high],L[(low+high)/2]);
while(low < high && L[high] >= key ) //若右边的大于枢轴
{
int tmp = high;
high--; //向前比较
if(L[tmp] < L[high])
{
return true; //判断真值
}
}
while(low < high && L[low] < key) //若左边的小于枢轴
{
int tmp = low;
low++; //向后比较
}
}
bool Left(SqList &L,int low,int high) //布尔型变量指示high从右向中间移动过程中是否进行交换记录的操作
{
int key = Index(L[low],L[high],L[(low+high)/2]);
while(low < high && L[high] >= key ) //若右边的大于枢轴
{
int tmp = high;
high--; //向前比较
}
while(low < high && L[low] < key) //若左边的小于枢轴
{
int tmp = low;
low++; //向后比较
if(L[tmp] > L[low])
{
return true;
}
}
}
int Partition(SqList &L,int low,int high) //返回枢轴所在位置,它之前的小于它
{ //之后的大于它
int key = Index(L[low],L[high],L[(low+high)/2]);
while(low < high) //判别条件,不满足时结束
{
while(low < high && L[high] >= key ) //若右边的大于枢轴
{
int tmp = high;
high--; //向前比较
if(L[tmp] < L[high]) //相邻两位比较大小
{
int exp = L[tmp];
L[tmp] = L[high];
L[high] = exp;
}
}
while(low < high && L[low] < key) //若左边的小于枢轴
{
int tmp = low;
low++; //向后比较
if(L[tmp] > L[low]) //相邻两位比较大小
{
int exp = L[tmp];
L[tmp] = L[low];
L[low] = exp;
}
}
}
return low; //返回此时位置
}
测试代码有了一定改变,如下所示:
void QuickSort(SqList &L,int low,int high) //快速排序
{
bool left = Left(L,low,high);
bool right = Right(L,low,high) ;
if(low < high)
{
int prvitloc = Partition(L,low,high); //将数组一分为二
if(!left) //若左半部分没有进行数值交换
{
QuickSort(L,low,prvitloc-1); //左半部分排序
}
if(!right) //若右半部分没有进行数值交换
{
QuickSort(L,prvitloc+1,high); //右半部分排序
}
}
}
三.简单选择排序
<span style="font-size:18px;"><strong><strong><span style="font-size:18px;">int SelectMinKey(SqList &L,int n,int key) //选择第key小的记录下标
{
for(int k = key+1;k < n;++k) //只比较key之后的
{
if(L[k] < L[key]) //若小于则记录下标
{
key = k;
}
}
return key; //返回下标
}
void SelectSort(SqList &L,int n) //简单选择排序
{
for(int i = 0;i < n-1;++i)
{
int j = SelectMinKey(L,n,i); //第key小的记录位置
if(i != j) //若不为此位置数,则交换位置
{
int tmp = L[i];
L[i] = L[j];
L[j] = tmp;
}
}
}</span></strong></strong></span>
四.堆排序
void Heapify(SqList &L,int low,int high)
{
int sq = L[low]; //将根结点保存在sq中
for(int j = 2*low;j <= high;j *= 2)
{
if(j < high && L[j] < L[j+1]) //沿关键字较大的孩子结点向下筛选
{
j++; //关键字较大节点下标
}
if(sq > L[j]) //若孩子结点的值小于根结点的值,则不进行交换
{
break;
}
L[low] = L[j];
low = j;
}
L[low] = sq; //将根结点插入到正确位置
}
void BuildHeap(SqList &L,int n) //建立大顶堆
{
for(int i = n/2;i > 0;i--) //从序号n/2开始建立大顶堆
{
Heapify(L,i,n);
}
}
void HeapSort(SqList &L,int n)
{ //对L[1..n]进行堆排序,不妨用L[0]做暂存单元
BuildHeap(L,n); //将L[1-n]建成初始堆
for(int i = n-1;i > 1;i--){
//对当前无序区L[1..i]进行堆排序,共做n-1趟。
L[0]=L[1];
L[1]=L[i];
L[i]=L[0];
//将堆顶和堆中最后一个记录交换
Heapify(L,1,i-1);
//将L[1..i-1]重新调整为堆,仅有L[1]可能违反堆性质
}
}
测试代码如下:
void main()
{
SqList sq = {0,53,24,35,56,32,78,99};
HeapSort(sq,8);
for(i = 1;i < 8; ++i)
{
cout<<sq[i]<<" ";
}
cout<<endl;
}
具体代码如上,如有任何问题请大家指出,谢谢。
如下附上完整版函数和测试代码:
#include <iostream>
using namespace std;
#define M 21
typedef int SqList[M];
void BubbleSort(SqList &L,int n) //冒泡排序
{
for(int i = 0;i < n-1;++i) //外层循环记录循环次数
{
for(int j = 0;j < n-i-1;++j) //内层循环记录每一次循环比较的次数
{ //(j<n-i-1)比较一次后,其后值不参与再比较
if(L[j] > L[j+1]) //若前者大于后者,则交换位置
{
int tmp = L[j];
L[j] = L[j+1];
L[j+1] = tmp;
}
}
}
}
//改进方法 L[low] L[high] L[(low+high)/2]从中找中间值作为枢值
int Index(int a,int b,int c) //查找作为枢值的值
{
if(a < b)
{
if(a < c)
{
if(b < c)
{
return b;
}
else
{
return c;
}
}
else
{
return a;
}
}
else //b <= a
{
if(c < a)
{
if(b < c)
{
return b;
}
else
{
return c;
}
}
else
{
return a;
}
}
}
/*int Partition(SqList &L,int low,int high) //返回枢轴所在位置,它之前的小于它
{ //之后的大于它
int key = Index(L[low],L[high],L[(low+high)/2]);
while(low < high) //判别条件,不满足时结束
{
while(low < high && L[high] >= key ) //若右边的大于枢轴
{
high--; //向前比较
}
int tmp = L[low]; //交换位置
L[low] = L[high];
L[high] = tmp;
while(low < high && L[low] < key) //若左边的小于枢轴
{
low++; //向后比较
}
tmp = L[low]; //交换位置
L[low] = L[high];
L[high] = tmp;
}
return low; //返回此时位置
}*/
//改进方法 L[low] L[high] L[(low+high)/2]从中找中间值作为枢值且在指针high增1和low减1时同时进行冒泡操作
//即在相邻两个纪录处于“逆序”时进行交换,同时算法中附设两个布尔型变量分别指示low和high在从两端向中间
//移动过程中是否进行交换记录的操作,若指针low在从低端向中间的移动过程中没有进行交换记录的操作,则不再
//需要对低端子表进行操作,同理高端子表类似
bool Right(SqList &L,int low,int high) //布尔型变量指示low从左向中间移动过程中是否进行交换记录的操作
{
int key = Index(L[low],L[high],L[(low+high)/2]);
while(low < high && L[high] >= key ) //若右边的大于枢轴
{
int tmp = high;
high--; //向前比较
if(L[tmp] < L[high])
{
return true; //判断真值
}
}
while(low < high && L[low] < key) //若左边的小于枢轴
{
int tmp = low;
low++; //向后比较
}
}
bool Left(SqList &L,int low,int high) //布尔型变量指示high从右向中间移动过程中是否进行交换记录的操作
{
int key = Index(L[low],L[high],L[(low+high)/2]);
while(low < high && L[high] >= key ) //若右边的大于枢轴
{
int tmp = high;
high--; //向前比较
}
while(low < high && L[low] < key) //若左边的小于枢轴
{
int tmp = low;
low++; //向后比较
if(L[tmp] > L[low])
{
return true;
}
}
}
int Partition(SqList &L,int low,int high) //返回枢轴所在位置,它之前的小于它
{ //之后的大于它
int key = Index(L[low],L[high],L[(low+high)/2]);
while(low < high) //判别条件,不满足时结束
{
while(low < high && L[high] >= key ) //若右边的大于枢轴
{
int tmp = high;
high--; //向前比较
if(L[tmp] < L[high]) //相邻两位比较大小
{
int exp = L[tmp];
L[tmp] = L[high];
L[high] = exp;
}
}
while(low < high && L[low] < key) //若左边的小于枢轴
{
int tmp = low;
low++; //向后比较
if(L[tmp] > L[low]) //相邻两位比较大小
{
int exp = L[tmp];
L[tmp] = L[low];
L[low] = exp;
}
}
}
return low; //返回此时位置
}
//改进方式,直接赋值
/*int Partition(SqList &L,int low,int high) //返回枢轴所在位置,它之前的小于它
{ //之后的大于它
int key = L[low]; //枢轴记录关键字
while(low < high) //判别条件,不满足时结束
{
while(low < high && L[high] >= key ) //若右边的大于枢轴
{
high--; //向前比较
}
L[low] = L[high]; //否则赋值
while(low < high && L[low] <= key) //若左边的小于枢轴
{
low++; //向后比较
}
L[high] = L[low]; //否则赋值
}
L[low] = key; //此时low = high,即可等价为L[high] = key,枢轴记录到位
return low; //返回此时位置
}*/
//交换方式
/*int Partition(SqList &L,int low,int high)
{
int key = L[low];
while(low < high)
{
while(low < high && L[high] >= key )
{
high--;
}
int tmp = L[low];
L[low] = L[high];
L[high] = tmp;
while(low < high && L[low] <= key)
{
low++;
}
tmp = L[low];
L[low] = L[high];
L[high] = tmp;
}
return low;
}*/
void QuickSort(SqList &L,int low,int high) //快速排序
{
bool left = Left(L,low,high);
bool right = Right(L,low,high) ;
if(low < high)
{
int prvitloc = Partition(L,low,high); //将数组一分为二
if(!left) //若左半部分没有进行数值交换
{
QuickSort(L,low,prvitloc-1); //左半部分排序
}
if(!right) //若右半部分没有进行数值交换
{
QuickSort(L,prvitloc+1,high); //右半部分排序
}
}
}
int SelectMinKey(SqList &L,int n,int key) //选择第key小的记录下标
{
for(int k = key+1;k < n;++k) //只比较key之后的
{
if(L[k] < L[key]) //若小于则记录下标
{
key = k;
}
}
return key; //返回下标
}
void SelectSort(SqList &L,int n) //简单选择排序
{
for(int i = 0;i < n-1;++i)
{
int j = SelectMinKey(L,n,i); //第key小的记录位置
if(i != j) //若不为此位置数,则交换位置
{
int tmp = L[i];
L[i] = L[j];
L[j] = tmp;
}
}
}
void Heapify(SqList &L,int low,int high)
{
int sq = L[low]; //将根结点保存在sq中
for(int j = 2*low;j <= high;j *= 2)
{
if(j < high && L[j] < L[j+1]) //沿关键字较大的孩子结点向下筛选
{
j++; //关键字较大节点下标
}
if(sq > L[j]) //若孩子结点的值小于根结点的值,则不进行交换
{
break;
}
L[low] = L[j];
low = j;
}
L[low] = sq; //将根结点插入到正确位置
}
void BuildHeap(SqList &L,int n) //建立大顶堆
{
for(int i = n/2;i > 0;i--) //从序号n/2开始建立大顶堆
{
Heapify(L,i,n);
}
}
void HeapSort(SqList &L,int n)
{ //对L[1..n]进行堆排序,不妨用L[0]做暂存单元
BuildHeap(L,n); //将L[1-n]建成初始堆
for(int i = n-1;i > 1;i--){
//对当前无序区L[1..i]进行堆排序,共做n-1趟。
L[0]=L[1];
L[1]=L[i];
L[i]=L[0];
//将堆顶和堆中最后一个记录交换
Heapify(L,1,i-1);
//将L[1..i-1]重新调整为堆,仅有L[1]可能违反堆性质
}
}
void main()
{
SqList sq = {0,53,24,35,56,32,78,99};
SqList sq2 = {53,24,35,56,32,78,99};
for(int i = 0;i < 7; ++i)
{
cout<<sq2[i]<<" ";
}
cout<<endl;
BubbleSort(sq2,7); //冒泡排序结果打印
for(i = 0;i < 7; ++i)
{
cout<<sq2[i]<<" ";
}
cout<<endl;
QuickSort(sq2,0,6); //快速排序
for(i = 0;i < 7; ++i)
{
cout<<sq2[i]<<" ";
}
cout<<endl;
SelectSort(sq2,7); //简单选择排序
for(i = 0;i < 7; ++i)
{
cout<<sq2[i]<<" ";
}
cout<<endl;
HeapSort(sq,8);
for(i = 1;i < 8; ++i)
{
cout<<sq[i]<<" ";
}
cout<<endl;
}