当前位置:   article > 正文

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

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

实验内容:

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

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

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

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

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

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

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


源码:

  1. #include <iostream>
  2. #include <string>
  3. using namespace std;
  4. #define MAXSIZE 100 /*参加排序元素的最大个数*/
  5. typedef struct list
  6. {
  7. int key;
  8. }RedType;
  9. typedef struct
  10. {
  11. RedType r[MAXSIZE + 1];
  12. int length; /*参加排序元素的实际个数*/
  13. }SqList;
  14. // 创建字符序列
  15. void CreateList(SqList& L) {
  16. cout << "请依次输入元素:" << endl;
  17. for (int i = 1;i < L.length + 1;i++)
  18. {
  19. cout << "第" << i << "个" << '\t';
  20. cin >> L.r[i].key;
  21. }
  22. }
  23. // 打印字符序列
  24. void PrintList(SqList& L)
  25. {
  26. cout << "排序后的元素序列为:";
  27. for (int i = 1;i < L.length + 1; i++)
  28. {
  29. cout << L.r[i].key;
  30. }
  31. cout << endl;
  32. }
  33. // 简单选择排序
  34. void slectOrder(SqList& L) {
  35. int min;
  36. for (int i = 1; i < L.length + 1;i++)
  37. {
  38. min = i;
  39. for (int j = i + 1;j < L.length + 1;j++) { // 从无序区选取最小元素
  40. if (L.r[min].key > L.r[j].key) {
  41. min = j; // 用k标记无序区中的最小元素
  42. }
  43. }
  44. if (min != i)
  45. {
  46. L.r[0] = L.r[i]; // R[0]临时存放R[i]
  47. L.r[i] = L.r[min]; // 将最小元素K放入有序区中正确的位置
  48. L.r[min] = L.r[0];
  49. }
  50. }
  51. PrintList(L);
  52. }
  53. // 直接插入排序
  54. void insertOrder(SqList& L) {
  55. int i, j;
  56. for (i = 1;i < L.length + 1;i++)
  57. {
  58. L.r[0] = L.r[i]; // 临时存放要比较的数
  59. j = i - 1; // 有序区最后一个元素
  60. while (j >= 0 && L.r[0].key < L.r[j].key)
  61. { // 如果当有序区的元素(从最后一个依次向前)大于要插入的元素
  62. L.r[j + 1] = L.r[j]; // 元素后移,以便于腾出一个位置插入tmp
  63. j--;
  64. }
  65. L.r[j + 1] = L.r[0]; // 在j+1位置处插入tmp,即R[j+1]
  66. }
  67. PrintList(L);
  68. }
  69. // 冒泡排序
  70. void bubleOrder(SqList& L) {
  71. for (int i = 1; i < L.length + 1; i++) {
  72. for (int j = 1; j < L.length + 1 - i; j++) {
  73. if (L.r[j].key > L.r[j + 1].key) {
  74. L.r[0] = L.r[j];
  75. L.r[j] = L.r[j + 1];
  76. L.r[j + 1] = L.r[0];
  77. }
  78. }
  79. }
  80. PrintList(L);
  81. }
  82. // 希尔排序
  83. void shellOrder(SqList& L) {
  84. int i, j, d;
  85. d = L.length + 1 / 2; // 增量初始值
  86. while (d > 0) // 循环到增量d=1为止
  87. {
  88. for (i = d + 1;i < L.length + 1;i++) // 对所有间隔d的位置进行排序
  89. {
  90. L.r[0] = L.r[i]; // 将i位置的元素暂时存放在0号位置
  91. j = i - d;
  92. while (j >= 1 && L.r[0].key < L.r[j].key)
  93. {
  94. L.r[j + d] = L.r[j]; // 对相隔d位置的元素组进行排序
  95. j = j - d; // 依次和前面的相隔d的倍数的位置进行比较并排序
  96. }
  97. L.r[j + d] = L.r[0]; // 插入元素
  98. }
  99. d = d / 2; // 减小增量
  100. }
  101. PrintList(L);
  102. }
  103. // 快速排序
  104. int Partition(SqList& L, int low, int high) {
  105. int pivotkey = L.r[low].key;
  106. while (low < high) {
  107. while (low < high && L.r[high].key >= pivotkey) {
  108. high--;
  109. }
  110. L.r[0] = L.r[low];
  111. L.r[low] = L.r[high];
  112. L.r[high] = L.r[0];
  113. while (low < high && L.r[low].key <= pivotkey) {
  114. low++;
  115. }
  116. L.r[0] = L.r[low];
  117. L.r[low] = L.r[high];
  118. L.r[high] = L.r[0];
  119. }
  120. return low;
  121. }
  122. void QSort(SqList &L, int low, int high) {
  123. int pivotloc;
  124. if (low < high) {
  125. pivotloc = Partition(L, low, high);
  126. QSort(L, low, pivotloc - 1);
  127. QSort(L, pivotloc + 1, high);
  128. }
  129. }
  130. void QuickSort(SqList &L) {
  131. QSort(L, 1, L.length);
  132. PrintList(L);
  133. }
  134. // 堆排序
  135. void Sift(SqList& L, int low, int high) // R[low...high]将其调整成堆结构
  136. {
  137. int i = low, j = 2 * i; // R[j]是R[i]的左孩子
  138. L.r[0] = L.r[i];
  139. while (j < high)
  140. {
  141. if (j < high && L.r[j].key < L.r[j + 1].key) { // 当左孩子小于右孩子时循环
  142. j++;
  143. }
  144. if (L.r[0].key < L.r[j].key) // 如果双亲节点小于孩子节点
  145. {
  146. L.r[i] = L.r[j]; // 将R[j]调整到双亲结点位置上
  147. i = j; // 修改i和j的值,以便继续向下前进
  148. j = 2 * i;
  149. }
  150. else { // 如果双亲节点都大于孩子节点,筛选结束
  151. break;
  152. }
  153. }
  154. L.r[i] = L.r[0]; // 将被筛选节点放入到最终位置
  155. }
  156. void HeapSort(SqList& L)
  157. {
  158. int i;
  159. for (i = L.length + 1 / 2; i >= 1; i--)
  160. Sift(L, i, L.length); // 循环建立初始堆
  161. for (i = L.length;i >= 2;i--) // 进行n-1次循环,完成堆排序
  162. {
  163. L.r[0] = L.r[1]; // 将第一个元素与当前区间内的元素进行互换
  164. L.r[1] = L.r[i];
  165. L.r[i] = L.r[0];
  166. Sift(L, 1, i - 1); // 筛选R[i]节点,得到i-1个节点的堆
  167. }
  168. PrintList(L);
  169. }
  170. // 折半插入排序
  171. void BInsertSort(SqList& L)
  172. {
  173. int i, j, low, high, mid;
  174. for (i = 1; i < L.length + 1; i++)
  175. {
  176. L.r[0] = L.r[i]; // 将L.R[i]暂时存放在L.R[0]
  177. low = 1;
  178. high = i - 1; // 在R[low...high]中查找需要插入的位置
  179. while (low <= high)
  180. {
  181. mid = (low + high) / 2; // 取中间位置进行比较
  182. if (L.r[0].key < L.r[mid].key) { // 当需要插入的元素在小于中间元素时
  183. high = mid - 1; // 缩小查找范围R[low...mid-1]
  184. }
  185. else { // 当需要插入的元素在大于等于中间元素时
  186. low = mid + 1; // 缩小查找范围R[mid+1...high]
  187. }
  188. }
  189. /*当找到合适的位置时,high = low = mid;则元素应该插入到high的后面;
  190. 那么high后面的元素应该后移,low应该插入到high+1*/
  191. for (j = i - 1; j >= high + 1; j--) { // 元素后移
  192. L.r[j + 1] = L.r[j];
  193. }
  194. L.r[high + 1] = L.r[0]; // 插入元素
  195. }
  196. PrintList(L);
  197. }
  198. int main() {
  199. // 根据输入字符序列创建排序序列
  200. SqList L;
  201. cout << "请输入元素个数: ";
  202. cin >> L.length;
  203. CreateList(L);
  204. // 输入操作序号
  205. int num;
  206. cout << "1.简单选择排序" << endl;
  207. cout << "2.直接插入排序" << endl;
  208. cout << "3.冒泡排序" << endl;
  209. cout << "4.希尔排序" << endl;
  210. cout << "5.快速排序" << endl;
  211. cout << "6.堆排序" << endl;
  212. cout << "7. 折半插入排序" << endl;
  213. cout << "8.退出";
  214. cout << endl;
  215. while (true)
  216. {
  217. cout << "请输入您要选择的计算: " << endl;
  218. cin >> num;
  219. switch (num)
  220. {
  221. case 1:
  222. {
  223. cout << "简单选择排序:" << endl;
  224. slectOrder(L);
  225. cout << endl;
  226. }break;
  227. case 2:
  228. {
  229. cout << "直接插入排序:" << endl;
  230. insertOrder(L);
  231. cout << endl;
  232. }break;
  233. case 3:
  234. {
  235. cout << "冒泡排序:" << endl;
  236. bubleOrder(L);
  237. cout << endl;
  238. }break;
  239. case 4:
  240. {
  241. cout << "希尔排序:" << endl;
  242. shellOrder(L);
  243. cout << endl;
  244. }break;
  245. case 5:
  246. {
  247. cout << "快速排序:" << endl;
  248. QuickSort(L);
  249. cout << endl;
  250. }break;
  251. case 6:
  252. {
  253. cout << "堆排序:" << endl;
  254. HeapSort(L);
  255. cout << endl;
  256. }break;
  257. case 7:
  258. {
  259. cout << "折半插入排序:" << endl;
  260. BInsertSort(L);
  261. }break;
  262. case 8:
  263. {
  264. cout << "退出成功!" << endl;
  265. system("pause");
  266. return 0;
  267. }break;
  268. default:
  269. {
  270. cout << "输入有误!请重新输入!" << endl;
  271. }
  272. }
  273. }
  274. system("pause");
  275. return 0;
  276. }

一、实验目的

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,系统退出,提示用户“退出成功!”;输入其他数字,提示用户"输入有误!请重新输入!"。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/一键难忘520/article/detail/973248
推荐阅读
相关标签
  

闽ICP备14008679号