【基础知识】7、排序算法 C++ 程序
排序算法程序
1、冒泡排序
通过对相邻数据的元素进行交换,逐步将待排序序列排成有序序列的过程。
如升序排列:
- 扫描整个待排序序列(非整个序列,不扫描已经排好的序列)
- 在一趟扫描中,最终必然将最大的元素排在待排序序列的末尾,这也是最大元素应该在的位置
- 第一趟排序之后,将最大的元素排在最后一个位置,第二趟将次大的放到倒数第二个位置…
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 10
//排序用的顺序表结构
typedef struct
{
int r[MAXSIZE + 1];
int length;
}SqList;
//交换两个值
void swap(SqList *L, int i, int j)
{
int temp = L->r[i];
L->r[i] = L->r[j];
L->r[j] = temp;
}
// 冒泡排序
void Bubblesort(SqList *L)
{
int i, j, p;
int flag = 1;
for (i = 1; i < L -> length && flag; i++)
{
flag = 0;
for (j = L->length - 1; j >= i; j--)
{
if (L->r[j]>L->r[j + 1])
{
swap(L, j, j + 1);
flag = 1;
}
}
printf("\n\n第%d次排序结果为:\n\n", i);
for (p = 1; p < L->length + 1; p++)
{
printf("%3d", L->r[p]);
}
}
}
int main()
{
int x, y;
SqList L;
L.length = 10;
printf("待排序的结果为:\n");
for (x = 1; x < 11; x++)
{
y = rand() % 10;
L.r[x] = y;
printf("%3d", y);
}
Bubblesort(&L);
getchar();
return 0;
}
输出:
#include<iostream>
using namespace std;
template<typename T>
void bubble( T t[],int len)//注意模板中的参数T为参数类型,所以不能写成T[]
{
bool flag=true;
int i,j;
for(i=1;i<=len-1&&flag;i++)
{
flag=false;
for(j=0;j<len-i;j++)//如果外层循环是从1开始,那么内层循环j<len-i,
//不能取等号,否则会产生下标越界,因为下面的交换判断语句为t[j]
//与t[j+1],
{
if(t[j]>t[j+1])
{
swap(t[j],t[j+1]);
flag=true;
}
}
}
}
void main()
{
int a[]={4,2,1,3,5,7,6};
char x[100]={'x','y','s','a','n','c','m'};//此处必须指定数组的大小,虽然不指定也不会出错,但是当用字符去初始化一个没定义长度的字符数组时,系统不会默认在
//末尾添加'\0',所以此时不能用strlen函数来求该字符数组的长度,而当指定数组的大小后,余下的系统自动赋值为空,即'\0'
// int len=strlen(a);错误,strlen函数的参数为char*类型
int len=sizeof(a)/4;
for(int i=0;i<len;i++)
cout<<a[i]<<' ';
cout<<endl;
cout<<"排序后结果为"<<endl;
bubble(a,len);
for(int i=0;i<len;i++)
cout<<a[i]<<' ';
cout<<endl;
int str_len=strlen(x);
for(int i=0;i<len;i++)
cout<<x[i]<<' ';
cout<<endl;
cout<<"排序后结果为"<<endl;
bubble(x,str_len);
for(int i=0;i<len;i++)
cout<<x[i]<<' ';
cout<<endl;
}
2、直接插入排序
基本操作是将一个记录插入到已经排好的有序表中,从而得到一个新的、记录增1的有序表。
也就是将第一个数作为已经排好的序列,第二个数是插入其左边还是右边的情况。
#include <iostream>
#include <stdlib.h>
#define MAXSIZE 10
//排序用的顺序表结构
typedef struct
{
int r[MAXSIZE + 1];//用于存储要排序数组,r[0]用做哨兵或临时变量
int length;
}SqList;
//交换两个值
void swap(SqList *L, int i, int j){
int temp = L->r[i];
L->r[i] = L->r[j];
L->r[j] = temp;
}
//直接插入排序
void InsertSort(SqList *L)
{
int i, j,p;
for (i = 2; i <= L->length; i++)
{
if (L->r[i] < L->r[i - 1])
{
L->r[0] = L->r[i]; //设置哨兵
for (j = i - 1; L->r[j]>L->r[0]; j--)
{
L->r[j + 1] = L->r[j];
}
L->r[j + 1] = L->r[0];
}
printf("\n\n第%d次排序结果为:\n\n", i);
for (p = 1; p < L->length + 1; p++)
{
printf("%3d", L->r[p]);
}
}
}
int main()
{
int x, y;
SqList L;
L.length = 10;
printf("待排序的序列为为:\n");
for (x = 1; x < 11; x++)
{
y = rand() % 10;
L.r[x] = y;
printf("%3d", y);
}
InsertSort(&L);
getchar();
return 0;
}
输出:
3、希尔排序
基于增量“inception”对序列进行分割
第一次:inception=length/3+1,i=inception+1,将第i位和第i-inception位比较
第二次:inception=inception/3+1,i=inception+1
直到inception=1为止
#include <iostream>
#include <stdlib.h>
#define MAXSIZE 10
//排序用的顺序表结构
typedef struct
{
int r[MAXSIZE + 1];//用于存储要排序数组,r[0]用做哨兵或临时变量
int length;
}SqList;
//交换两个值
void swap(SqList *L, int i, int j){
int temp = L->r[i];
L->r[i] = L->r[j];
L->r[j] = temp;
}
//直接插入排序
void ShellSort(SqList *L)
{
int i, j, p;
int increment = L->length;
do
{
increment = increment / 3 + 1;
for (i = increment + 1; i < L->length; i++)
{
if (L->r[i] < L->r[i - increment])
{
L->r[0]=L->r[i];
for (j = i - increment; j>0 && L->r[0] < L->r[j]; j = j - increment)
L->r[j + increment] = L -> r[j];
L->r[j + increment] = L->r[0];
}
}
printf("\n\n第%d次排序结果为:\n\n", i-increment);
for (p = 1; p < L->length + 1; p++)
{
printf("%3d", L->r[p]);
}
}
while (increment > 1);
}
int main()
{
int x, y;
SqList L;
L.length = 10;
printf("待排序的序列为为:\n");
for (x = 1; x < 11; x++)
{
y = rand() % 10;
L.r[x] = y;
printf("%3d", y);
}
ShellSort(&L);
getchar();
return 0;
}
4、快速排序
快速排序作为和冒泡排序相同类型的排序(同为交换类排序),之所以能够被人们所熟知,是因为它解决了冒泡排序只用来对相邻两个元素进行比较,因此在互换两个相邻元素时只能消除一个逆序,而快速排序是通过两个不相邻元素的交换,来消除待排序记录中的多个逆序。即快速排序中的一趟交换可以消除多个逆序。
具体思想:
从待排序记录中选取一个记录(通常选取第一个记录,当然也可采用随机划分的方式,这样能大大提高快速排序的执行效率,如我们所熟知的在O(n)的时间复杂度内找出前k元的算法),将其关键字记为K1,然后将其余关键字小于K1的记录移到前面,而大于关键字K1的移到后面。
一趟快速排序之后,将待排序序列划分为两个子表,最后将关键字K1插到这两个子表的分界线的位置。具体实现就是用三层while循环,最外层的while循环控制该趟快速是否进行,而内层的两个while循环一个用来从左到右扫描大于该趟基准记录关键字的元素,一个用来从右到左扫描小于该趟基准记录的关键字的元素,可以用两个指针low和high指向当前从左到右和从右到左扫描的当前记录的关键字,找到一个就将其交换。
以上是一趟快速排序的思想,对上述划分后的子表重复上述过程,直至划分后的子表的长度不超过1为止。即为快速排序的思想,从定义可知快速排序是一个递归排序。
#include <iostream>
#include <stdlib.h>
#define MAXSIZE 10
//排序用的顺序表结构
typedef struct
{
int r[MAXSIZE + 1];//用于存储要排序数组,r[0]用做哨兵或临时变量
int length;
}SqList;
//交换两个值
void swap(SqList *L, int i, int j)
{
int temp = L->r[i];
L->r[i] = L->r[j];
L->r[j] = temp;
}
void QuickSort(SqList *L);
void QSort(SqList *L, int low, int high);
int Partition(SqList *L, int low, int high);
int main()
{
int x, y;
SqList L;
L.length = 10;
printf("待排序的序列为:\n");
for (x = 1; x < 11; x++)
{
y = rand() % 10;
L.r[x] = y;
printf("%3d", y);
}
QuickSort(&L);
getchar();
return 0;
}
//快速排序
void QuickSort(SqList *L)
{
QSort(L, 1, L->length);
}
void QSort(SqList *L, int low, int high)
{
int pivot,p;
if (low < high)
{
pivot = Partition(L, low, high);
QSort(L, low, pivot - 1);
QSort(L, pivot + 1, high);
}
}
int Partition(SqList *L, int low, int high)
{
int pivotkey;
pivotkey = L->r[low];
while (low < high)
{
while (low < high && L->r[high] >= pivotkey)
{
high--;
}
swap(L, low, high);
while (low < high && L->r[low] <= pivotkey)
{
low++;
}
swap(L, low, high);
}
return low;
}
5、总结
稳定性:排序算法的稳定性:若待排序的序列中,存在多个具有相同关键字的记录,经过排序, 这些记录的相对次序和排序之前相同,则称该算法是稳定的;
若排序后,记录的相对次序和排序前不同,则该算法是不稳定的。
稳定的排序算法:冒泡排序、插入排序、归并排序和基数排序
不是稳定的排序算法:选择排序、快速排序、希尔排序、堆排序
当待排序序列顺序或基本有序时,直接插入排序和冒泡排序将大大减少比较次数和移动记录的次数,时间复杂度可降至O(n);
而快速排序则相反,当待排序序列基本有序时,将蜕化为冒泡排序,时间复杂度提高为O(n2);
待排序序列是否有序,对简单选择排序、堆排序、归并排序和基数排序的时间复杂度影响不大。
下面是转于别人的程序
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100
//排序用的顺序表结构
typedef struct{
int r[MAXSIZE + 1];//用于存储要排序数组,r[0]用做哨兵或临时变量
int length;
}SqList;
//交换两个值
void swap(SqList *L, int i, int j){
int temp = L->r[i];
L->r[i] = L->r[j];
L->r[j] = temp;
}
//冒泡排序
void BubbleSort(SqList *L){
int i, j, k = 0, l = 0;
for (i = 1; i<L->length; i++){//外层循环,确定所有数都与其它数比较
//k++;
for (j = i + 1; j <= L->length; j++){//内层循环,用一个数跟其它数比较大小
k++;
if (L->r[i] > L->r[j]){
swap(L, i, j);
l = l + 3;
}
}
}
printf("冒泡排序中关键字的比较次数为%d:", k);
printf("\n冒泡排序中关键字的移动次数为%d:", l);
printf("\n");
}
//直接排序
void InsertSort(SqList *L) {
int i, j, k = 0, l = 0;
for (i = 2; i <= L->length; i++){
k++;
if (L->r[i] < L->r[i - 1]){
L->r[0] = L->r[i];//设置哨兵
l++;
for (j = i - 1; L->r[j] > L->r[0]; j--){
L->r[j + 1] = L->r[j];//记录后移
l++;
k++;
}
k++;//这一步容易忽略,跳出循环的时候,是比较了一次,不符合条件才跳出的
L->r[j + 1] = L->r[0];//插入到正确位置
l++;
}
}
printf("直接排序中关键字的比较次数为%d:", k);
printf("\n直接排序中关键字的移动次数为%d:", l);
printf("\n");
}
//简单选择排序
void SelectSort(SqList *L){
int i, j, min;
int k = 0, l = 0;
for (i = 1; i<L->length; i++){
//k++;
min = i;
for (j = i + 1; j <= L->length; j++){
k++;
if (L->r[min] > L->r[j]){
min = j;
}
}
if (i != min){//判断 i!min,则证明有数据比 r[min]还要小,则需交换
swap(L, i, min);
l = l + 3;
}
}
printf("简单排序中关键字的比较次数为:%d", k);
printf("\n简单排序中关键字的移动次数为:%d", l);
printf("\n");
}
//希尔排序
void ShellSort(SqList *L) {
int i, j;
int k = 0, l = 0;
int increment = L->length;
do{
increment = increment / 5 + 1;//增量序列
for (i = increment + 1; i <= L->length; i++){
k++;
if (L->r[i] < L->r[i - increment]){// 需要将L->r[i]插入有序增量子表
L->r[0] = L->r[i];
l++;
for (j = i - increment; L->r[0]<L->r[j] && j>0; j = j - increment){
k++;
L->r[j + increment] = L->r[j];
l++;
}
k++;//这一步容易忽略,跳出循环的时候,是比较了一次,不符合条件才跳出的
L->r[j + increment] = L->r[0];
l++;
}
}
} while (increment > 1);
printf("希尔排序中关键字的比较次数为:%d", k);
printf("\n希尔排序中关键字的移动次数为:%d", l);
printf("\n");
}
//已知L->r[s..m]中记录的关键字除L->r[s]之外均满足堆的定义
//本函数调整L->r[s]的关键字,使L->r[s..m]成为一个大顶堆
void HeapAdjust(SqList *L, int s, int m, int &a, int &b){
int temp, j;
temp = L->r[s];
b++;
for (j = 2 * s; j <= m; j = j * 2){
a++;
if (L->r[j] < L->r[j + 1] && j<m)
++j;//j为关键字中较大的记录的下标
a++;
if (temp >= L->r[j])
break;
L->r[s] = L->r[j];
b++;
s = j;
}
L->r[s] = temp;
b++;
}
//堆排序
void HeapSort(SqList *L) {
int i;
int k = 0, l = 0;
for (i = L->length / 2; i>0; i--){//把L中的r构建成一个大顶堆
HeapAdjust(L, i, L->length, k, l);
}
for (i = L->length; i>1; i--){
swap(L, 1, i);//将堆顶记录和当前未经排序子序列的最后一个记录交换
l = l + 3;
HeapAdjust(L, 1, i - 1, k, l);//将L->r[1...i-1]重新调整为大顶堆
}
printf("堆排序中关键字的比较次数为:%d", k);
printf("\n堆排序中关键字的移动次数为:%d", l);
printf("\n");
}
//交换顺序表L中子表的记录,使枢轴记录到位,并返回其所在位置
//此时在它之前(后)的记录均不大(小)于它
int Partition(SqList *L, int low, int high, int &k, int &l){
int pivotkey;
pivotkey = L->r[low];
while (low<high){
while (L->r[high] >= pivotkey && low<high){
k++;
high--;
}
k++;//这一步容易忽略,跳出循环的时候,是比较了一次,不符合条件才跳出的
swap(L, low, high);
l = l + 3;
while (L->r[low] <= pivotkey && low<high){
k++;
low++;
}
k++;//这一步容易忽略,跳出循环的时候,是比较了一次,不符合条件才跳出的
swap(L, low, high);
l = l + 3;
}
return low;
}
//对顺序表L中的子序列L->r[low..high]作快速排序
void QSort(SqList *L, int low, int high, int &k, int &l){
int pivot;//枢轴
if (low<high){
pivot = Partition(L, low, high, k, l);//将L->r[low..high]一分为二,算出枢轴值
QSort(L, low, pivot - 1, k, l);//对低子表递归排序
QSort(L, pivot + 1, high, k, l);//对高子表递归排序
}
}
//快速排序
void QuickSort(SqList *L) {
int k = 0, l = 0;
QSort(L, 1, L->length, k, l);
printf("快速排序中关键字的比较次数为:%d", k);
printf("\n快速排序中关键字的移动次数为:%d", l);
printf("\n");
}
int main(){
int x, y;
SqList L, L1, L2, L3, L4, L5;
L.length = 100;
for (int i = 0; i<5; i++){
printf("第%d次待排序列为:\n", i + 1);
for (x = 1; x<101; x++) {
y = rand() % 100;
L.r[x] = y;
printf("%3d", y);
}
L1 = L2 = L3 = L4 = L5 = L;
//fflush(stdin);
printf("\n排序后的结果\n");
BubbleSort(&L);
printf("直接排序后的结果\n");
InsertSort(&L1);
printf("简单排序后的结果\n");
SelectSort(&L2);
printf("希尔排序后的结果\n");
ShellSort(&L3);
printf("堆排序后的结果\n");
HeapSort(&L4);
printf("快速排序后的结果\n");
QuickSort(&L5);
for (x = 1; x<101; x++) {
printf("%3d", L.r[x]);
}
printf("\n");
}
while (1){//设置一个死循环,为了不让程序结束而关闭窗口
}
return 0;
}
相关文章
- C++学习——c++逗号操作符说明(附加全部运算符优先级)
- 干货 | OpenCV获取不规则区域的最大内切圆(附Python / C++ 源码)
- 女朋友要去面试 C++,我建议她这么做
- C++基本概念_c语言 c++区别
- c++的链表-C++链表
- c++的链表-链表入门(C++)
- 【C++】函数 指针类型参数 与 引用类型参数 对比 ( 修改外部变量需要传入的参数要求 | 参数作返回值 )
- 【C++修炼之路】3. 类和对象(中)
- 82页《现代C++教程》:高速上手C++ 11/14/17/20
- C++ 测试框架 GoogleTest 初学者入门篇 丙
- 队列的存储结构的实现(C/C++实现)详解编程语言
- C++ search_n(STL search_n)搜索算法详解
- C++ cin:读取键盘输入的数据
- 关于C++内存中字节对齐问题的详细介绍
- C++中“#”号的使用技巧
- C++构造双向链表的实现代码
- C++clock()解析如何使用时钟计时的应用
- C++创建桌面快捷方式开始菜单的实现代码
- 深入解析C++中的指针数组与指向指针的指针