您的位置:首页 > 科技 > 能源 > 数据结构实验:排序算法(附c++源码:冒泡、选择、希尔、快速、堆排序)

数据结构实验:排序算法(附c++源码:冒泡、选择、希尔、快速、堆排序)

2024/10/5 19:13:38 来源:https://blog.csdn.net/sherry__yuzu/article/details/141098842  浏览:    关键词:数据结构实验:排序算法(附c++源码:冒泡、选择、希尔、快速、堆排序)

实验内容:

输入一组关键字序列,分别实现下列排序算法:

1.编写函数,实现简单选择排序、直接插入排序和冒泡排序算法。

2.编写函数,实现希尔排序算法。

3.编写函数,实现快速排序算法。

4.编写函数,实现堆排序算法。

5.编写函数,实现折半插入排序算法。

6.编写一个主函数,在主函数中设计一个简单的菜单,分别调试上述算法。


源码:

#include <iostream>
#include <string>
using namespace std;#define MAXSIZE 100 /*参加排序元素的最大个数*/typedef struct list
{int key;
}RedType;typedef struct
{RedType r[MAXSIZE + 1];int length; /*参加排序元素的实际个数*/
}SqList;// 创建字符序列
void CreateList(SqList& L) {cout << "请依次输入元素:" << endl;for (int i = 1;i < L.length + 1;i++){cout << "第" << i << "个" << '\t';cin >> L.r[i].key;}
}// 打印字符序列
void PrintList(SqList& L)
{cout << "排序后的元素序列为:";for (int i = 1;i < L.length + 1; i++){cout << L.r[i].key;}cout << endl;
}// 简单选择排序
void slectOrder(SqList& L) {int min;for (int i = 1; i < L.length + 1;i++){min = i;for (int j = i + 1;j < L.length + 1;j++) { // 从无序区选取最小元素if (L.r[min].key > L.r[j].key) {min = j; // 用k标记无序区中的最小元素}}if (min != i){L.r[0] = L.r[i]; // R[0]临时存放R[i]L.r[i] = L.r[min]; // 将最小元素K放入有序区中正确的位置L.r[min] = L.r[0];}}PrintList(L);
}// 直接插入排序
void insertOrder(SqList& L) {int i, j;for (i = 1;i < L.length + 1;i++){L.r[0] = L.r[i]; // 临时存放要比较的数j = i - 1; // 有序区最后一个元素while (j >= 0 && L.r[0].key < L.r[j].key){ // 如果当有序区的元素(从最后一个依次向前)大于要插入的元素L.r[j + 1] = L.r[j]; // 元素后移,以便于腾出一个位置插入tmpj--;}L.r[j + 1] = L.r[0]; // 在j+1位置处插入tmp,即R[j+1]}PrintList(L);
}// 冒泡排序
void bubleOrder(SqList& L) {for (int i = 1; i < L.length + 1; i++) {for (int j = 1; j < L.length + 1 - i; j++) {if (L.r[j].key > L.r[j + 1].key) {L.r[0] = L.r[j];L.r[j] = L.r[j + 1];L.r[j + 1] = L.r[0];}}}PrintList(L);
}// 希尔排序
void shellOrder(SqList& L) {int i, j, d;d = L.length + 1 / 2; // 增量初始值while (d > 0) // 循环到增量d=1为止{ for (i = d + 1;i < L.length + 1;i++) // 对所有间隔d的位置进行排序{L.r[0] = L.r[i]; // 将i位置的元素暂时存放在0号位置j = i - d;while (j >= 1 && L.r[0].key < L.r[j].key){L.r[j + d] = L.r[j]; // 对相隔d位置的元素组进行排序j = j - d; // 依次和前面的相隔d的倍数的位置进行比较并排序}L.r[j + d] = L.r[0]; // 插入元素}d = d / 2; // 减小增量}PrintList(L);
}// 快速排序
int Partition(SqList& L, int low, int high) {int pivotkey = L.r[low].key;while (low < high) {while (low < high && L.r[high].key >= pivotkey) {high--;}L.r[0] = L.r[low];L.r[low] = L.r[high];L.r[high] = L.r[0];while (low < high && L.r[low].key <= pivotkey) {low++;}L.r[0] = L.r[low];L.r[low] = L.r[high];L.r[high] = L.r[0];}return low;
}void QSort(SqList &L, int low, int high) {int pivotloc;if (low < high) {pivotloc = Partition(L, low, high);QSort(L, low, pivotloc - 1);QSort(L, pivotloc + 1, high);}
}void QuickSort(SqList &L) {QSort(L, 1, L.length);PrintList(L);
}// 堆排序
void Sift(SqList& L, int low, int high) // R[low...high]将其调整成堆结构
{int i = low, j = 2 * i; // R[j]是R[i]的左孩子L.r[0] = L.r[i];while (j < high){if (j < high && L.r[j].key < L.r[j + 1].key) { // 当左孩子小于右孩子时循环j++;}if (L.r[0].key < L.r[j].key) // 如果双亲节点小于孩子节点{L.r[i] = L.r[j]; // 将R[j]调整到双亲结点位置上i = j; // 修改i和j的值,以便继续向下前进j = 2 * i;}else { // 如果双亲节点都大于孩子节点,筛选结束break; }}L.r[i] = L.r[0]; // 将被筛选节点放入到最终位置
}void HeapSort(SqList& L)
{int i;for (i = L.length + 1 / 2; i >= 1; i--)Sift(L, i, L.length); // 循环建立初始堆for (i = L.length;i >= 2;i--) // 进行n-1次循环,完成堆排序{L.r[0] = L.r[1]; // 将第一个元素与当前区间内的元素进行互换L.r[1] = L.r[i];L.r[i] = L.r[0];Sift(L, 1, i - 1); // 筛选R[i]节点,得到i-1个节点的堆}PrintList(L);
}// 折半插入排序
void BInsertSort(SqList& L)
{int i, j, low, high, mid;for (i = 1; i < L.length + 1; i++){L.r[0] = L.r[i]; // 将L.R[i]暂时存放在L.R[0]low = 1;high = i - 1; // 在R[low...high]中查找需要插入的位置while (low <= high){mid = (low + high) / 2; // 取中间位置进行比较if (L.r[0].key < L.r[mid].key) { // 当需要插入的元素在小于中间元素时high = mid - 1; // 缩小查找范围R[low...mid-1]}else { // 当需要插入的元素在大于等于中间元素时low = mid + 1; // 缩小查找范围R[mid+1...high]}}/*当找到合适的位置时,high = low = mid;则元素应该插入到high的后面;那么high后面的元素应该后移,low应该插入到high+1。*/for (j = i - 1; j >= high + 1; j--) { // 元素后移L.r[j + 1] = L.r[j];}L.r[high + 1] = L.r[0]; // 插入元素}PrintList(L);
}int main() {// 根据输入字符序列创建排序序列SqList L;cout << "请输入元素个数: ";cin >> L.length;CreateList(L);// 输入操作序号int num;cout << "1.简单选择排序" << endl;cout << "2.直接插入排序" << endl;cout << "3.冒泡排序" << endl;cout << "4.希尔排序" << endl;cout << "5.快速排序" << endl;cout << "6.堆排序" << endl;cout << "7. 折半插入排序" << endl;cout << "8.退出";cout << endl;while (true){cout << "请输入您要选择的计算: " << endl;cin >> num;switch (num){case 1: {cout << "简单选择排序:" << endl;slectOrder(L);cout << endl;}break;case 2: {cout << "直接插入排序:" << endl;insertOrder(L);cout << endl;}break;case 3:{cout << "冒泡排序:" << endl;bubleOrder(L);cout << endl;}break;case 4: {cout << "希尔排序:" << endl;shellOrder(L);cout << endl;}break;case 5: {cout << "快速排序:" << endl;    QuickSort(L);cout << endl;}break;case 6:{cout << "堆排序:" << endl;  HeapSort(L);cout << endl;}break;case 7:{cout << "折半插入排序:" << endl;    BInsertSort(L);}break;case 8:{cout << "退出成功!" << endl;system("pause");return 0;}break;default:{cout << "输入有误!请重新输入!" << endl;}}}system("pause");return 0;
}

一、实验目的

1. 掌握常见的排序算法(插入排序、交换排序、选择排序、归并排序、基数排序等)的思想、特点及其适用条件

2. 熟练掌握常见的排序算法的程序实现


二、问题分析及数据结构设计

1. 问题分析

输入一组关键字序列,实现下列排序算法:简单选择排序、直接插入排序、冒泡排序、希尔排序、快速排序、堆排序、折半插入排序算法。需要我们掌握堆的数据结构,二分法等,知道排序的递归和非递归算法的实现。

2. 数据结构设计

参加排序元素的最大个数:MAXSIZE 100;

排序元素类型:list,别名RedType,包括元素值:key--整型;

排序序列类型:SqList,包含length--整型,表示参加排序元素的实际个数、

r[MAXSIZE + 1]--RedType类型,存放待排序的元素。

(其中r[0]为哨兵,不参与实际排序,实际排序的元素从r[1]开始)


三、算法设计(伪代码表示)

1. 输入字符序列 创建待排序序列

Function createList(SqList& L)

Begin

For i = 1 -> 序列长度 + 1;i++

cin >> 序列.第i个元素.值key

End

2. 打印字符序列

Function PrintList(SqList& L)

Begin

For i = 1 -> 序列长度 + 1;i++

cout >> 序列.第i个元素.值key

End

3. 简单选择排序

Function SelectOrder(SqList& L)

Begin

For i = 1 -> 序列长度 + 1;i++

最小下标 = i

For j = i + 1 -> 序列长度 + 1;j++

IF 序列.最小下标的元素.值key > 序列.第j个元素.值key

最小值 = j

IF 最小下标 != i

序列.第0个元素 = 序列.第i个元素

序列.第i个元素 = 序列.最小下标的元素

序列.最小下标的元素 = 序列.第0个元素

PrintList(SqList L)

End

4. 直接插入排序

Function InsertOrder(SqList& L)

Begin

For i = 1 -> 序列长度 + 1;i++

序列.第0个元素 = 序列.第i个元素

j = i - 1

WHILE j >= 0 && 序列.第0个元素.值key < 序列.第j个元素.值key

序列.第j + 1个元素 = 序列.第j 个元素

j--

序列.第j + 1个元素 = 序列.第0个元素

PrintList(SqList L)

End

5. 冒泡排序

Function bubleOrder(SqList& L)

Begin

For i = 1 -> 序列长度 + 1;i++

For j = 1 -> 序列长度 + 1;j++

IF 序列.第j个元素.值key > 序列.第j + 1个元素.值key

序列.第0个元素.值key > 序列.第j 个元素.值key

序列.第j个元素.值key > 序列.第j + 1个元素.值key

序列.第j + 1个元素.值key > 序列.第0个元素.值key

PrintList(SqList L)

End

6. 希尔排序

Function shellOrder(SqList& L)

Begin

d = 序列.长度 + 1 / 2

WHILE d > 0

For i = d + 1 -> 序列.长度 + 1;i++

序列.第0个元素 = 序列.第i个元素

j = i - d

WHILE j >= 1 && 序列.第0个元素.值key < 序列.第j个元素.值key

序列.第j + d个元素 = 序列.第j个元素

j = j - d

序列.第j + d个元素 = 序列.第0个元素

d = d / 2

PrintList(SqList L)

End

7. 快速排序

7.1

Function Partition(SqList& L, int low, int high)

Begin

Pivotkey = 序列.左指针所在元素.值key

WHILE 左指针 < 右指针

WHILE 左指针 < 右指针 && 序列.右指针所在元素.值key >= 序列.左指针所在元素.值key

右指针左移

序列.第0个元素 = 序列.左指针所在元素

序列.左指针所在元素 = 序列.右指针所在元素

序列.右指针所在元素 = 序列.第0个元素

WHILE 左指针 < 右指针 && 序列.左指针所在元素.值key <= 序列.左指针所在元素.值key

左指针右移

序列.第0个元素 = 序列.右指针所在元素

序列.右指针所在元素 = 序列.左指针所在元素

序列.左指针所在元素 = 序列.第0个元素

Return low

End

7.2

Function Qsort(SqList& L, int low, int high)

Begin

IF 左指针 < 右指针

Pivotloc = Partition(L,low,high)

Qsort(L,low,Pivotloc - 1)

Qsort(L,Pivotloc + 1,high)

End

7.3

Function QuickSort(SqList& L)

Begin

Qsort(L,1,序列.长度)

PrintList(SqList L)

End

8. 堆排序

8.1

Function Sift(SqList& L, int low, int high)

Begin

I = low

J = 2 * i

序列.第0个元素 = 序列.第i个元素

WHILE j < high

IF j < high && 序列.第j个元素.值key < 序列.第j + 1个元素.值key

J++

IF 序列.第0个元素.值key < 序列.第j个元素.值key

序列.第i个元素 = 序列.第j个元素

I = j

J = 2 * i

ELSE break

序列.第i个元素 = 序列.第0个元素

End

8.2

Function HeapSort(SqList& L)

Begin

For i = 序列.长度 + 1 / 2 -> i = 1;i--

Sift(L,i,序列.长度)

For i = 序列.长度 -> 2;i--

序列.第0个元素 > 序列.第1 个元素

序列.第1个元素 > 序列.第i个元素

序列.第i个元素 > 序列.第0个元素

Sift(L,1,i - 1)

PrintList(SqList L)

End

9. 折半插入排序

Function BInsertSort(SqList& L)

Begin

For i = 1 -> 序列.长度 + 1;i++

序列.第0个元素 = 序列.第i个元素

区间下限 = 1

区间上限 = i - 1

WHILE 区间下限 <= 区间上限

中间位置 = 下限 + 上限 / 2

IF 序列.第0个元素.值key < 序列.中间元素.值key

上限 = 中间位置 - 1

ELSE

下限 = 中间位置 + 1

For j = i - 1 -> 上限 + 1;j--

序列.第j + 1个元素 = 序列.第j个元素

序列.上限 + 1个元素 = 序列.第0个元素

PrintList(SqList L)

End


四、功能模块程序流程图

1. 菜单

 

说明:菜单功能首先提示用户输入数字。

输入数字1,代表简单选择排序,提示用户输入元素个数,以及第几个元素,以此建立排序序列,最后输出序列的简单排序的结果;

输入数字2,代表直接插入排序,提示用户输入元素个数,以及第几个元素,以此建立排序序列,最后输出序列的直接插入排序的结果;

输入数字3,代表冒泡排序,提示用户输入元素个数,以及第几个元素,以此建立排序序列,最后输出序列的冒泡排序的结果;

输入数字4,代表希尔排序,提示用户输入元素个数,以及第几个元素,以此建立排序序列,最后输出序列的希尔排序的结果;

输入数字5,代表快速排序,提示用户输入元素个数,以及第几个元素,以此建立排序序列,最后输出序列的快速排序的结果;

输入数字6,代表堆排序,提示用户输入元素个数,以及第几个元素,以此建立排序序列,最后输出序列的堆排序的结果;

输入数字7,代表折半插入排序,提示用户输入元素个数,以及第几个元素,以此建立排序序列,最后输出序列的折半插入排序的结果;

输入数字8,系统退出,提示用户“退出成功!”;

输入其他数字,提示用户"输入有误!请重新输入!"。

2. 简单选择排序

说明:该函数目的为对序列进行简单选择排序,提示用户输入元素个数,以及第几个元素,以此建立排序序列,最后输出序列的简单选择排序的结果。

3. 直接插入排序

说明:该函数目的为对序列进行直接插入排序,提示用户输入元素个数,以及第几个元素,以此建立排序序列,最后输出序列的直接插入排序的结果。

4. 冒泡排序

说明:该函数目的为对序列进行冒泡排序,提示用户输入元素个数,以及第几个元素,以此建立排序序列,最后输出序列的冒泡排序的结果。

5. 希尔排序

说明:该函数目的为对序列进行希尔排序,提示用户输入元素个数,以及第几个元素,以此建立排序序列,最后输出序列的希尔排序的结果。

6. 快速排序

说明:该函数目的为对序列进行快速排序,提示用户输入元素个数,以及第几个元素,以此建立排序序列,最后输出序列的快速排序的结果。

7. 堆排序

说明:该函数目的为对序列进行堆排序,提示用户输入元素个数,以及第几个元素,以此建立排序序列,最后输出序列的堆排序的结果。

8. 折半插入排序

说明:该函数目的为对序列进行折半插入排序,提示用户输入元素个数,以及第几个元素,以此建立排序序列,最后输出序列的折半插入排序的结果。


五、实验结果

1. 简单选择排序:

分析:输入数字1后进入该对刚刚输入的排序序列进行简单选择排序的功能。首先提示用户输入元素个数,以及第几个元素,以此建立排序序列,最后输出序列的简单选择排序的结果。接着提示用户继续选择想要的计算。

2. 直接插入排序:

分析:输入数字2后进入该对刚刚输入的排序序列进行直接插入排序的功能。首先提示用户输入元素个数,以及第几个元素,以此建立排序序列,最后输出序列的直接插入排序的结果。接着提示用户继续选择想要的计算。

3. 冒泡排序:

分析:输入数字3后进入该对刚刚输入的排序序列进行冒泡排序的功能。首先提示用户输入元素个数,以及第几个元素,以此建立排序序列,最后输出序列的冒泡的结果。接着提示用户继续选择想要的计算。

4. 希尔排序:

分析:输入数字4后进入该对刚刚输入的排序序列进行希尔排序的功能。首先提示用户输入元素个数,以及第几个元素,以此建立排序序列,最后输出序列的希尔排序的结果。接着提示用户继续选择想要的计算。

5. 快速排序:

分析:输入数字5后进入该对刚刚输入的排序序列进行快速排序的功能。首先提示用户输入元素个数,以及第几个元素,以此建立排序序列,最后输出序列的快速排序的结果。接着提示用户继续选择想要的计算。

6. 堆排序:

分析:输入数字6后进入该对刚刚输入的排序序列进行堆排序的功能。首先提示用户输入元素个数,以及第几个元素,以此建立排序序列,最后输出序列的堆排序的结果。接着提示用户继续选择想要的计算。

7. 折半插入排序:

分析:输入数字7后进入该对刚刚输入的排序序列进行折半插入排序的功能。首先提示用户输入元素个数,以及第几个元素,以此建立排序序列,最后输出序列的折半插入排序的结果。接着提示用户继续选择想要的计算。

8. 退出:

分析:输入数字8后进入该退出系统的功能,提示用户退出成功。退出成功后,不会再出现提示用户继续输入想要选择的运算。

9. 输入其他数字:

分析:输入其他数字后进提示用户输入有误,请重新输入。并再次提示用户继续输入想要选择的运算。


六、算法分析

1. 简单选择排序:

核心思想是在未排序的序列中找到最小的元素,然后将其放到序列的起始位置。

接着,再从剩余未排序的序列中找到最小的元素,放到已排序序列的末尾。

重复这个过程,直到整个序列都被排序。

2. 直接插入排序:

核心思想是将一个待排序的元素插入到已经排好序的部分序列中,使得插入之后的序列仍然保持有序。

即从第二个元素开始,依次将后面的元素插入到已排好序的序列中,直到所有元素都被插入。

3. 冒泡排序:

核心思想是利用外层和内层两个for循环,外层for循环代表总共比较的趟数,内层for循环代表每趟比较的次数。

从第一个元素开始,依次比较相邻的两个元素,如果顺序不对就交换它们的位置,这样一轮下来,最大的元素就放在了最后。

然后,对剩下的n-1个元素重复上述过程,直到所有元素都排好序。

3. 希尔排序:

首先确定一个增量序列,通常选择增量刚开始为d = n/2,其中n为待排序序列的长度。

然后根据增量序列,将待排序的序列分割成若干个子序列,对每个子序列进行插入排序

。每次缩小增量为上次的d/2,重复上述步骤,直到增量为1,完成最后一次插入排序。

4. 快速排序:

选择一个序列中的第一个元素为基准元素,然后将序列分割成两个子序列,一个子序列中的元素都小于基准元素,另一个子序列中的元素都大于基准元素。

递归地对两个子序列进行排序,当子序列的长度为1或0时,递归结束。

5. 堆排序:

将待排序的序列看作是一个完全二叉树的顺序存储结构,从最后一个非叶子节点开始,依次向前调整,使得每个节点都满足双亲节点的值大于孩子节点的值,以此构建大根堆。

将大根堆的根节点(即序列中的最大元素)与堆的最后一个节点交换位置,然后将剩余的n-1个元素重新调整为最大堆。

重复这个过程,直到整个序列都排好序。

6. 折半插入排序:

核心思想是从第二个元素开始,将当前元素插入到已排序的子序列中。

使用二分查找法在已排序的子序列中找到插入位置。

将插入位置之后的元素后移一位,然后将当前元素插入到找到的位置。


七、操作说明

编译后首先出现一个菜单,1-8有文字信息描述不同的排序的相关算法,提示用户输入1-8之间的数字。输入数字1,代表对刚刚输入的排序序列进行简单选择排序;输入数字2,代表对刚刚输入的排序序列进行直接插入排序;输入数字3,代表对刚刚输入的排序序列进行冒泡排序;输入数字4,代表对刚刚输入的排序序列进行希尔排序;输入数字5,代表对刚刚输入的排序序列进行快速排序;输入数字6,代表对刚刚输入的排序序列进行堆排序;输入数字7,代表对刚刚输入的排序序列进行折半插入排序;输入数字8,系统退出,提示用户“退出成功!”;输入其他数字,提示用户"输入有误!请重新输入!"。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com