前言
这是数据结构的实验四的题目。
为了自己能在繁杂的文件中顺利、快速地找到自己熟悉的排序、查找算法代码,故借CSDN平台存放本人写的代码。另外,还请有缘看到此文章的同行们能多多指点。
非常感谢。
1 各种排序算法的实现
用随机函数生成16个2位正整数(10~99),实现 插入排序、 选择排序、 冒泡排序、 双向冒泡、 快速排序、 二路归并排序 等多种排序算法,输出排序中间过程、统计关键字的比较次数和记录的移动次数。
1.1 代码
代码说明:
各排序算法在同一个cpp文件中,要查看某个算法时可以把main函数中的相应排序算法的注释符号“//”去掉即可;
#include<iostream>
#include<ctime>
using namespace std;
const int maxnum = 1000;
//数组结构
typedef struct sqlist
{
int l[maxnum];
int length;
}sqlist;
//------插入排序-----(采用“从后向前比较”策略)
void InsertSort(sqlist list, int length)
{
int compare_count = 0; //关键字比较次数
int remove_count = 0; //关键字移动次数
int process = 1; //第n次中间过程
for (int i = 2; i <= list.length; i++) {
compare_count++; //关键字比较次数+1
if (list.l[i] < list.l[i - 1]) {
list.l[0] = list.l[i]; // list.l[0]: 人称“哨兵”
list.l[i] = list.l[i - 1]; //将list.[i]后移
int j = 0;
for (j = i - 2; list.l[0] < list.l[j]; j--) {
list.l[j + 1] = list.l[j]; //将记录逐个后移
}
list.l[j + 1] = list.l[0]; //将“哨兵”插入到正确的位置
remove_count++; //关键字移动次数+1
}
//中间过程输出
cout << "第" << process++ << "次中间过程输出:" << endl;
for (int i = 1; i <= list.length; i++) {
cout << list.l[i] << ' ';
}
cout << endl;
}
//输出关键字比较次数和关键字移动次数
cout << "关键字比较次数:" << compare_count << "\t"
<< "关键字移动次数:" << remove_count << endl;
}
//-----选择排序-----
void SelectSort(sqlist& list)
{
int k = 0;
int process = 1; //第n次中间过程
int compare_count = 0; //关键字比较次数
int remove_count = 0; //关键字移动次数
for (int i = 1; i < list.length; i++) {
k = i;
for (int j = i + 1; j <= list.length; j++) {
compare_count++; //关键字比较次数+1
if (list.l[j] < list.l[k]) k = j; //寻找数组剩余未排序元素中的值最小元素的下标
if (k != i) {
remove_count++; //关键字移动次数+1
int temp = list.l[i];
list.l[i] = list.l[k];
list.l[k] = temp;
}
}
//中间过程输出
cout << "第" << process++ << "次中间过程输出:" << endl;
for (int i = 1; i <= list.length; i++) {
cout << list.l[i] << ' ';
}
cout << endl;
}
//输出关键字比较次数和关键字移动次数
cout << "关键字比较次数:" << compare_count << "\t"
<< "关键字移动次数:" << remove_count << endl;
}
//-----冒泡排序-----
void BubbleSort(sqlist& list)
{
int n = list.length; //作为结束循环的条件之一
int flag = 1; //是否排序完成的标记
int process = 1; //第n次中间过程
int compare_count = 0; //关键字比较次数
int remove_count = 0; //关键字移动次数
//设置两重循环
while (n--&&flag) {
flag = 0;
for (int j = 1; j < list.length; j++) {
compare_count++; //关键字比较次数+1
if (list.l[j] > list.l[j + 1]) {
remove_count++; //关键字移动次数+1
flag = 1;
int temp = list.l[j];
list.l[j] = list.l[j + 1];
list.l[j + 1] = temp;
}
}
//中间过程输出
cout << "第" << process++ << "次中间过程输出:" << endl;
for (int i = 1; i <= list.length; i++) {
cout << list.l[i] << ' ';
}
cout << endl;
}
//输出关键字比较次数和关键字移动次数
cout << "关键字比较次数:" << compare_count << "\t"
<< "关键字移动次数:" << remove_count << endl;
}
//-----双向冒泡----
void TwowaybubbleSort(sqlist& list)
{
int n = list.length;
int flag = 1;
int process = 1; //第n次中间过程
int compare_count = 0; //关键字比较次数
int remove_count = 0; //关键字移动次数
int left= 1; //初始化待排序数组的最左端元素序号
int right= list.length; //初始化待排序数组的最右端元素序号
int temp_right = 0; //暂存待更新待排序数组的最右端元素序号
int temp_left = 0; //暂存待更新待排序数组的最左端元素序号
//设置两重循环
while (n--&&flag) {
flag = 0;
for ( int j = left; j < right; j++) {
compare_count++; //关键字比较次数+1
if (list.l[j] > list.l[j + 1]) {
flag = 1;
remove_count++; //关键字移动次数+1
int temp = list.l[j];
list.l[j] = list.l[j + 1];
list.l[j + 1] = temp;
temp_right = j;
}
}
right = temp_right; //更新待排序数组的最右端元素序号
for (int j = right; j >left; j--) {
compare_count++; //关键字比较次数+1
if (list.l[j] < list.l[j-1]) {
flag = 1;
remove_count++; //关键字移动次数+1
int temp = list.l[j];
list.l[j] = list.l[j - 1];
list.l[j - 1] = temp;
temp_left = j;
}
}
left = temp_left; //更新待排序数组的最左端元素序号
//中间过程输出
cout << "第" << process++ << "次中间过程输出:" << endl;
for (int i = 1; i <= list.length; i++) {
cout << list.l[i] << ' ';
}
cout << endl;
cout << "left,right:" << left << ' ' << right << endl;
}
//输出关键字比较次数和关键字移动次数
cout << "关键字比较次数:" << compare_count << "\t"
<< "关键字移动次数:" << remove_count << endl;
}
//-----快速排序-----
int QSort_process = 1; //第n次中间过程
int QSort_compare_count = 0; //关键字比较次数
int QSort_remove_count = 0; //关键字移动次数
void QSort(sqlist& list,int low, int high)
{
int i, j, pivotkey;
i = low;
j = high;
if (low < high){
pivotkey = list.l[low]; //设置枢轴
while (i != j){
while (j > i&& list.l[j] >= pivotkey){
--j;
QSort_compare_count++; //关键字比较次数+1
}
if (i < j){
list.l[i] = list.l[j]; //交换
++i;
QSort_remove_count++; //关键字移动次数+1
}
while (i < j && list.l[i] <= pivotkey){
++i;
QSort_compare_count++; //关键字比较次数+1
}
if (i < j){
list.l[j] = list.l[i]; //交换
--j;
QSort_remove_count++; //关键字移动次数+1
}
}
list.l[i] = pivotkey; //枢轴记录到位
//中间过程输出
cout << "第" << QSort_process++ << "次中间过程输出:" << endl;
for (int n = 1; n <= list.length; n++) {
cout << list.l[n] << ' ';
}
cout << endl;
//递归
QSort(list, low, i - 1);
QSort(list, i + 1, high);
}
}
//-----二路归并排序-----
int MSort_process = 1; //第n次中间过程
int MSort_compare_count = 0; //关键字比较次数
int MSort_remove_count = 0; //关键字移动次数
void Merge(sqlist &list, int low, int mid, int high)
{
int len = high - low + 1;
int* temp = new int[len];
int i = low; int j = mid + 1; //i,j分别为两个子序列的下标
int k = 0; //新合并的数组的下标
while (i <= mid && j <= high) {
if (list.l[i] <= list.l[j]) {
MSort_compare_count++; //关键字比较次数+1
MSort_remove_count++; //关键字移动次数+1
temp[k] = list.l[i];
i++;
k++;
}
else {
MSort_compare_count++; //关键字比较次数+1
MSort_remove_count++; //关键字移动次数+1
temp[k] = list.l[j];
j++;
k++;
}
}
while (i <= mid) {
temp[k] = list.l[i];
i++;
k++;
}
while (j <= high) {
temp[k] = list.l[j];
j++;
k++;
}
for (int i = 0; i < len; i++) {
list.l[low+i] = temp[i];
}
}
void MSort(sqlist &list,int low,int high)
{
if (low < high) {
int mid = (low + high) / 2;
//递归
MSort(list, low, mid);
MSort(list, mid + 1, high);
//合并左右序列(子树)
Merge(list, low, mid, high);
}
//中间过程输出
cout << "第" << MSort_process++ << "次中间过程输出:" << endl;
for (int n = 1; n <= list.length; n++) {
cout << list.l[n] << ' ';
}
cout << endl;
}
int main()
{
/*
-----------------------------------------
说明:
随机生成数组首元素下标为 1
-----------------------------------------
*/
// 生成随机数组
srand(unsigned(time));
sqlist list;
list.length = 0;
cout << "请输入生成数组的长度:";
cin >> list.length; //输入数组的长度
cout << "生成的数组为:";
for (int i = 1; i <=list.length; i++){
list.l[i] =(int) rand() % 90 + 10;
cout << list.l[i]<<' ';
}
cout << endl;
//-----插入排序-----
//InsertSort(list,list.length);
//-----选择排序-----
//SelectSort(list);
//-----冒泡排序-----
//BubbleSort(list);
//-----双向冒泡-----
//TwowaybubbleSort(list);
//-----快速排序-----
//QSort(list, 1, list.length);
//输出关键字比较次数和关键字移动次数
//cout << "关键字比较次数:" << QSort_compare_count << "\t"
// << "关键字移动次数:" << QSort_remove_count << endl;
//-----归并排序-----
//MSort(list, 1, list.length);
//输出关键字比较次数和关键字移动次数
//cout << "关键字比较次数:" << MSort_compare_count << "\t"
//<< "关键字移动次数:" << MSort_remove_count << endl;
}
1.2 运行结果
- 插入排序
- 选择排序
- 冒泡排序
- 双向冒泡排序
- 快速排序
- 归并排序
2 各种查找算法的实现
2.1 顺序查找
使用数组或链表结构。用随机函数生成16个不重复的字母(’a’~’z’),键盘输入待查找的字母,返回查找成功与否,若成功则返回该字母所在的位置(序号),并计算比较次数。
2.1.1 代码
#include<iostream>
#include<ctime>
using namespace std;
//-----顺序查找-----
void Search_Seq(char* s)
{
cout << "请输入想寻找的字母:";
char x;
cin >> x; //输入想找的字母
int index = 0;
int count = 0; //比较次数,初始化为0
while (s[index] != '\0') {
++count;
if (s[index++] == x) {
cout << "已找到字母 " << x << " ,它的下标为:" << index - 1 << endl;
break;
}
}
if (count == 17) {
cout << "没有找到该字母,共比较了:" << count-1 << " 次"<< endl;
}
else cout << "共比较了:" << count << " 次";
}
int main()
{
/*
-----------------------------------------
说明:
随机生成数组首元素下标为 0
-----------------------------------------
*/
// 生成随机数组
srand(unsigned(time));
char* s=new char[17]; //字符数组
for (int i = 0; i < 16; i++) s[i] = '\0';
cout << "生成的数组为:";
int k = 0;
while (k != 16) {
int flag = 0; //用于检测是否有相同的字母出现
s[k] = 'a' + (rand() % 26);
for (int i = 0; i < 16; i++) {
if (k != i) {
if (s[k] == s[i]) flag = 1; //若flag=1,则重新加入一个字母
}
}
if (flag == 0) ++k; //若flag=0,往数组下一个位置添加字母
}
for (int i = 0; i < 16; i++)
cout << s[i] << " "; //打印随机生成的字符数组
s[16] = '\0'; //字符串的最后一位是'\0'
cout << endl;
//-----顺序查找-----
Search_Seq(s);
}
2.1.2 运行结果
- 查找成功
- 查找失败
2.2 折半查找
用数组实现,查找前元素先排序。计算比较次数。分别用查找成功、不成功进行测试。
2.2.1 代码
#include<iostream>
#include<ctime>
using namespace std;
//-----顺序查找-----
void TwowaybubbleSort(char* s)
{
int n = 16;
int flag = 1; //检测是否已排序完成
int left = 1; //初始化待排序数组的最左端元素序号
int right = 15; //初始化待排序数组的最右端元素序号
int temp_right = 0; //暂存待更新待排序数组的最右端元素序号
int temp_left = 0; //暂存待更新待排序数组的最左端元素序号
//设置两重循环
while (n-- && flag) {
flag = 0;
for (int j = left; j < right; j++) {
if (s[j] > s[j + 1]) {
flag = 1;
int temp = s[j];
s[j] =s[j + 1];
s[j + 1] = temp;
temp_right = j;
}
}
right = temp_right; //更新待排序数组的最右端元素序号
for (int j = right; j > left; j--) {
if (s[j] < s[j - 1]) {
flag = 1;
int temp = s[j];
s[j] = s[j - 1];
s[j - 1] = temp;
temp_left = j;
}
}
}
}
void Search_Bin(char* s)
{
TwowaybubbleSort(s); //先使用双向冒泡进行排序
int compare_count = 0; //记录比较次数
cout << "请输入想寻找的字母:";
char x;
cin >> x; //输入待寻找的字母
int low = 0; int high = 15;
int mid = 0;
while (low <= high) {
mid = (low + high) / 2;
if (x == s[mid]) {
compare_count++;
cout << "已找到字母 " << x << endl;
break;
}
else if (x < s[mid]) {
compare_count++;
high = mid - 1;
}
else {
compare_count++;
low = mid + 1;
}
}
if(low>high&&x!=s[low]) cout<< "未找到该字母,总共比较了 " << compare_count << " 次" << endl;
else cout << "总共比较了 " << compare_count << " 次" << endl;
}
int main()
{
/*
-----------------------------------------
说明:
随机生成数组首元素下标为 0
-----------------------------------------
*/
// 生成随机数组
srand(unsigned(time));
char* s = new char[17]; //字符数组
for (int i = 0; i < 16; i++) s[i] = '\0';
cout << "生成的数组为:";
int k = 0;
while (k != 16) {
int flag = 0; //用于检测是否有相同的字母出现
s[k] = 'a' + (rand() % 26);
for (int i = 0; i < 16; i++) {
if (k != i) {
if (s[k] == s[i]) flag = 1; //若flag=1,则重新加入一个字母
}
}
if (flag == 0) ++k; //若flag=0,往数组下一个位置添加字母
}
for (int i = 0; i < 16; i++)
cout << s[i] << " "; //打印随机生成的字符数组
s[17] = '\0'; //字符串的最后一位是'\0'
cout << endl;
//-----折半查找-----
Search_Bin(s);
}
2.2.2 运行结果
- 查找成功
- 查找失败
2.3 二叉查找树
手工输入10个字母,生成一棵二叉查找树,用递归算法打印树结构或分别输出先序和中序遍历序列以确认其结构。键盘输入待查找的字母,计算比较次数。分别用查找成功、不成功进行测试.
2.3.1 代码
#include<iostream>
using namespace std;
//二叉查找树结构
typedef struct BSTNode
{
char data;
BSTNode* lchild, * rchild;
}BSTNode,*BSTree;
//二叉排序树的插入
void InsertBST(BSTree& T, char x)
{
if (!T) {
BSTNode* new_tree = new BSTNode; //生成新结点
new_tree->data = x;
new_tree->lchild = new_tree->rchild = NULL;
T = new_tree;
}
else if (x < T->data) InsertBST(T->lchild, x);
else if (x > T->data) InsertBST(T->rchild, x);
}
//二叉排序树的创建
void CreatBST(BSTree& T)
{
T = NULL;
char x;
cin >> x;
int i = 0; //用于提示已经输入了多少个字母
while (x != '#') {
InsertBST(T, x);
cout << "这是输入的第 " << ++i << " 个字母" << endl;
cin >> x;
}
}
//二叉树的先序遍历
void Preorder(BSTree T)//前序遍历(递归实现)
{
if (T != NULL)
{
cout << T->data << " ";
Preorder(T->lchild);
Preorder(T->rchild);
}
}
//二叉树的中序遍历
void Mreorder(BSTree T)//前序遍历(递归实现)
{
if (T != NULL)
{
Mreorder(T->lchild);
cout << T->data << " ";
Mreorder(T->rchild);
}
}
//-----二叉查找树-----
int compare_count = 0; //全局变量。记录比较次数
BSTree SearchBST(BSTree T, char x)
{
compare_count++;
if (!T|| x == T->data) {
if (!T)
cout << "查询失败,共查找了 " << compare_count << " 次\n";
else
cout << "已找到字母 " << T->data << " ,共查找了 " << compare_count << " 次\n";
return T;
}
else if (x < T->data) return SearchBST(T->lchild, x);
else if (x >= T->data) return SearchBST(T->rchild, x);
}
int main()
{
//创建二叉查找树
BSTree T = new BSTNode;
cout << "请输入十个字母(输入#结束): " << endl;
CreatBST(T);
cout<<"输入完成\n";
//中序遍历二叉查找树
cout << "\n先序遍历输出:";
Preorder(T);
//中序遍历二叉查找树
cout << "\n中序遍历输出(按照各字母的ASCⅡ码大小):";
Mreorder(T);
//输入待查找字母
cout << "\n请输入想查询的字母(如果想退出查找,请输入$) ";
char letter;
cin >> letter;
//查找字母
while (1 && letter != '$') {
SearchBST(T, letter);
cout << "\n请输入想查询的字母(如果想退出查找,请输入$) ";
cin >> letter;
}
}
2.3.2 运行结果
查找成功和失败都在同一张截图里了。