数据结构实验一:线性表,堆栈和队列实现
数据结构实验二 :二叉树的操作与实现
数据结构实验三: 图的操作与实现
数据结构实验四 : 查找和排序算法实现
文章目录
一、实验目的:
1、领会折半查找的过程和算法设计;
2、领会二叉排序树的定义,二叉树排序树的创建、查找和删除过程及其算法设计;
3、领会快速排序的过程和算法设计;
4、领会堆排序的过程和算法设计;
5、掌握二路归并排序算法及其应用。
二、使用仪器、器材
微机一台
操作系统:WinXP
编程软件:C/C++编程软件
二、实验内容及原理
1、教材P362实验题2:实现折半查找的算法
编写一个程序exp9-2.cpp,输出在顺序表(1,2,3,4,5,6,7,8,9,10)中采用折半查找方法查找关键字9的过程。
#include<iostream>
using namespace std;
//编写一个程序exp9 - 2.cpp,
//输出在顺序表(1,2,3,4,5,6,7,8,9,10)
//中采用折半查找方法查找关键字9的过程
void search(int *arr,int key,int length) {
int left = 0;
int right = length;
int findway = 0;
while (left <= right) {//==时还有一位需要查找
int mid = (left + right) / 2;//取中点
findway++;
cout << "第" << findway << "次查找: " << arr[mid]<<endl;
if (arr[mid] < key) {
left = mid + 1; //左边界 = 中点+1
}else if(arr[mid]>key) {
right = mid - 1;
}else {
cout << "找到key:" << arr[mid]<<endl;//右边界 = 中点-1;
return;
}
}
cout << "未找到key"<<endl;
}
int main() {
int arr[ ]={ 1,2,3,4,5,6,7,8,9,10 };
cout << "查找关键字:9 " << endl;
search(arr, 9, 10);
return 0;
}
2、教材P362实验题4:实现二叉排序树的基本运算算法
编写一个程序bst.cpp,包含二叉排序树的创建、查找和删除算法,再次基础上编写exp9-4.cpp程序完成以下功能。
由关键字序列(4,9,0,1,8,6,3,5,2,7)创建一棵二叉排序bt并以括号表示法输出。
判断bt是否为一棵二叉排序树。
采用递归和非递归两种方法查找关键字为6的结点,并输出其查找路径。
分别删除bt中关键字为4和5的结点,并输出删除后的二叉排序。
#include<iostream>
using namespace std;
//编写一个程序bst.cpp, 包含二叉排序树的创建、查找和删除算法,再次基础上编写exp9 - 4.cpp程序完成以下功能。
//(1)由关键字序列(4,9,0,1,8,6,3,5,2,7)创建一棵二叉排序bt并以括号表示法输出。
//(2)判断bt是否为一棵二叉排序树。
//(3)采用递归和非递归两种方法查找关键字为6的结点,并输出其查找路径。
//(4)分别删除bt中关键字为4和5的结点,并输出删除后的二叉排序。
struct TreeNode
{
int value;
TreeNode* left;
TreeNode* right;
TreeNode(int v) {
this->value = v;
this->right = NULL;
this->left = NULL;
}
};
void insert(TreeNode*&root,int key) {
//如果root为空新建
if (!root) {
TreeNode* New = new TreeNode(key);
root = New;
return;
}
TreeNode* cur = root;
TreeNode* pre = NULL;
while (cur != NULL) {//循环找到key所在的位置 记录 pre 和now
//判断大小等于情况
//大于
if (key > cur->value) {//大于往右
pre = cur;
cur = cur->right;
}
else if (key < cur->value) {//小于往左
pre = cur;
cur = cur->left;
}
else {//相等赋值
cur->value = key;
return;
}
}
//已经找到cur==NULL 为插入位置
TreeNode* temp = new TreeNode(key);
if (key<pre->value) {
pre->left = temp;
}
else if (key>pre->value) {
pre->right = temp;
}
//创建新节点 ,如果> 右节点 <左节点
}
/*建树
*/
void creat_tree(TreeNode*&root,int *arr,int length) {
for (int i = 0; i < length; i++) {
insert(root, arr[i]);
}
cout << "建树成功" << endl;
}
/*
*括号输出树
*/
void bracketingPrint(TreeNode*root) {
//树空 ,直接返回
if (!root) {
return;
}
//输出当前节点的值
cout << root->value;
//如果右子树或右子树存在 输出(
if(root->left||root->right){
cout << "(";
//递归左子树
bracketingPrint(root->left);
if (root->right) {//如果右子树存在 先递归右子树,再输出)
cout << ",";
bracketingPrint(root->right);
}
cout << ")";//直接输出)
}
}
/*
* 判断是否二叉排序树
*/
//满足左子树的值小于父节点的值&& 右子树的值大于父节点的值
bool checkIfBST(TreeNode*root, int minLimit = 0x80000000, int maxLimit = 0x7fffffff){//初始化最大最小值
//头为空 返回true;
if (!root)return true;
//如果( 左边的值大于或等于minLsit 或者 右边的值小于等于 maxLimit) return false
if (root->value <= minLimit || root->value >= maxLimit)return false;
//返回 递归左右子树判断结果的并集 用父节点更新最大最小值
return checkIfBST(root->left, minLimit, root->value) && checkIfBST(root->right, root->value, maxLimit);
}
/*
* 递归查找
*/
void recursiveSearch(TreeNode*root,int key) {
//根空失败,返回
if (!root) {
cout << "查找失败" << endl;
return;
}
if (root->value == key) {//找到 返回
cout <<"->" << key << endl;
cout << "查找成功" << endl;
return;
}
//找到 返回
//左右递归
cout << root->value << "->"<<endl;//打印路径
if (key < root->value) {
recursiveSearch(root->left, key);
}else if(key>root->value){
recursiveSearch(root->right, key);
}
}
/*
* 非递归查找
*/
void no_recursiveSearch(TreeNode*root,int key) {
//while循环 当前节点root不空 值不等
while (root && root->value != key) {
// 打印路径
cout << root->value << "->"<<endl;
// 判断大小更新当前结单root
if (root->value > key) {//左
root = root->left;
}
else if (root->value<key) {//右
root = root->right;
}
}
//当前节点空查找失败返回
if (!root) {
cout << "查找失败" << endl;
}//不空说明&&值相对 说明找到
else {
cout << "->" << key << endl;
cout << "查找成功" << endl;
}
}
/*
* 删除节点
* //非递归查找到要换的节点
//找到的节点三种情况
//1.节点左孩子为空
// 1.1节点为根节点
// 1.2结单为左孩子
// 1.3结点为右孩子
//2.右孩子为空
// 1.1结点为根节点
// 1.2结单为左孩子
// 1.3结点为右孩子
//3.左右孩子不为空 (后继法)
// goatp记录当前find goat记录find->right
// 当goat的左孩子非空 更新goatp和goat
// 两种情况
// 1.goat(还是find的右孩子)是goatp(还是find)的右孩子 ,goat的左子树为空
// goat是要删除的目标,goatp的右孩子指向goat的右孩子
// 2.goat是goatp的左孩子,此时goat的左孩子为空,用goat的右孩子代替goatp的左孩子
*/
void DeleteNode(TreeNode*&root,int key) {
//非递归查找到要换的节点
if (!root) {
return;
}
TreeNode* find = root;
TreeNode* parents = NULL;//前驱
while (find!=NULL) {
if (find->value < key) {//往右找
parents = find;
find = find->right;
}
else if (find->value>key) {//
parents = find;
find = find->left;
}
else {//找到
//找到的节点三种情况:1节点左孩子为空 2右孩子为空 3左右孩子不为空
//1.节点左孩子为空
if (find->left == NULL) {
// 1.1节点为根节点
if (find == root) {
root = find->right;
return;
}
else if (find == parents->left) {// 1.2结单为左孩子
parents->left = find->right;
}
else if (find == parents->right) {// 1.3结点为右孩子
parents->right = find->right;
}
}
else if (find->right==NULL) {//2.右孩子为空
if (find == root) {// 1.1结点为根节点
root = find->left;
}
else if (find==parents->left) {// 1.2结单为左孩子
parents->left = find->left;
}
else if (find==parents->right) {// 1.3结点为右孩子
parents->right = find->left;
}
}
else {//3.左右孩子不为空 (后继法)
TreeNode* goatparents = find; //后继目标的父
TreeNode* goat = find->right; //后继目标起点
// goatp记录当前find goat记录find->right
while (goat->left != NULL) { // 当goat的左孩子非空 更新goatp和goat
goatparents = goat;
goat = goat->left;
}
//将goat的值给find
find->value = goat->value;// 两种情况
if (goatparents->right == goat) {
// 1.goat(还是find的右孩子)是goatp(还是find)的右孩子 ,goat的左子树为空
// goat是要删除的目标,goatp的右孩子指向goat的右孩子
goatparents->right = goat->right;
}
else if (goatparents->left == goat) {
// 2.goat是goatp的左孩子,此时goat的左孩子为空,用goat的右孩子代替goatp的左孩子
goatparents->left = goat->right;
}
}
return;
}
}
}
int main() {
cout << "(1)由关键字序列(4,9,0,1,8,6,3,5,2,7)创建一棵二叉排序bt并以括号表示法输出。" << endl;
cout << endl;
int arr[] = { 4,9,0,1,8,6,3,5,2,7 };
TreeNode* bt=NULL;
creat_tree(bt, arr, sizeof(arr) / sizeof(arr[0]));//造树
bracketingPrint(bt);//括号打印
cout << endl;
//=========================================================
cout << "(2)判断bt是否为一棵二叉排序树。" << endl;
if (checkIfBST(bt)) {
cout << "这是一颗二叉排序树" << endl;
}
else {
cout << "这不是一颗二叉排序树" << endl;
}
cout << endl;
//=========================================================
cout << "(3)采用递归和非递归两种方法查找关键字为6的结点,并输出其查找路径。" << endl;
cout << "递归查找:" << endl;
recursiveSearch(bt, 6);
cout << endl;
cout << "非递归查找:" << endl;
no_recursiveSearch(bt, 6);
cout << endl;
//=========================================================
cout << "(4)分别删除bt中关键字为4和5的结点,并输出删除后的二叉排序。" << endl;
DeleteNode(bt, 4);
DeleteNode(bt, 5);
cout << endl;
bracketingPrint(bt);
cout << endl;
return 0;
}
3、实现快速排序算法
编写一个程序exp4-3.cpp实现快速排序算法,用相关数据进行测试并输出各趟的排序结果。
#include<iostream>
using namespace std;
void fastSearch(int*arr,int left,int right) {
//left>right
if (left>right) {
return;
}
//后寻找
int temp = arr[left];
int l = left;
int r = right;
while (l<r) {
//循环,左小于右,比temp大
while (l<r && arr[r]>=temp) {
r--;
}//循环,左小于右,比temp小
while (l < r && arr[l] <= temp) {
l++;
}
//交换中间和开头值
if (l < r) {
int temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;
}
}
arr[left] = arr[l];
arr[l] = temp;
//递归左右
fastSearch(arr, left, l - 1);//左
fastSearch(arr, l + 1, right);
}
int main() {
int arr[100], n;
cout << "请输入数列中的元素个数 n 为:" << endl;
cin >> n;
cout << "请依次输入数列中的元素:" << endl;
for (int i = 0; i < n; i++)
{
cin >> arr[i];
}
cout << "原数据:" << endl;
for (int i = 0; i < n; i++) {
cout << arr[i] << ",";
}
fastSearch(arr, 0, n-1);
cout<<endl;
cout << "排序后" << endl;
for (int i = 0; i < n; i++) {
cout << arr[i]<<",";
}
return 0;
}
4、教材P397实验题7:实现堆排序算法
编写一个程序exp10-7.cpp实现堆排序算法,用相关数据进行测试并输出各趟的序结果。
#include<iostream>
using namespace std;
/*
* 交换函数
*/
void swap(int* arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
/*
* 调整堆
*/
void adjustHeap(int* arr, int top, int length) {
//记录top
int temp = arr[top];
//取左孩子 int k =top*2+1
for (int k = top * 2 + 1; k <length; k = k * 2 + 1) {
//如果右孩子大 指向右孩子
if (k + 1 < length && arr[k + 1] > arr[k]) {
k++;
}
if (arr[k] > temp) {
arr[top] = arr[k];
top = k;
}//如果比孩子小 跳出
else {
break;
}
}
// 深度完 将top给叶子k
arr[top] = temp;
}
/*
* 对排序
*/
void HeapSort(int*arr,int length) {
//建大顶堆
for (int i = length / 2 - 1; i >= 0; i--) {
adjustHeap(arr, i, length);
}
//交换+调整大顶堆
for (int j = length - 1; j >0; j--) { //进行n-1次
swap(arr, 0, j);
adjustHeap(arr, 0, j);
}
}
int main() {
int arr[100], n;
cout << "请输入数列中的元素个数 n 为:" << endl;
cin >> n;
cout << "请依次输入数列中的元素:" << endl;
for (int i = 0; i < n; i++)
{
cin >> arr[i];
}
cout << "排序前:" << endl;
for (int i = 0; i < n ; i++) {
cout << arr[i] << ",";
}
cout << endl;
HeapSort(arr, n);
cout << "排序后:" << endl;
for (int i = 0; i < n; i++) {
cout <<arr[i] << ",";
}
cout << endl;
return 0;
}
5、实现二路归并排序算法。
编写一个程序exp4-5.cpp,采用二路归并排序方法,对有n个记录的待排序序列(例如8个记录的序列{8, 2, 21, 34, 12, 32, 6, 16, 11, 5})进行排序,要求(1)写出采用二路归并排序方法进行排序的过程;(2)写出二路归并排序算法程序;(3)给出二路归并排序算法的时间复杂度和稳定性。
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cmath>
using namespace std;
/*
* 合并函数
*/
void merge(int* a, int low, int mid, int hight) //合并函数
{
int* b = new int[hight - low + 1]; //用 new 申请一个辅助函数
int i = low, j = mid + 1, k = 0; // k为 b 数组的小标
while (i <= mid && j <= hight)
{
if (a[i] <= a[j])
{
b[k++] = a[i++]; //按从小到大存放在 b 数组里面
}
else
{
b[k++] = a[j++];
}
cout << endl;
for (int x = 0; x < k;x++) {
cout << b[x] << ",";
}
cout << endl;
}
while (i <= mid) // j 序列结束,将剩余的 i 序列补充在 b 数组中
{
b[k++] = a[i++];
}
while (j <= hight)// i 序列结束,将剩余的 j 序列补充在 b 数组中
{
b[k++] = a[j++];
}
k = 0; //从小标为 0 开始传送
for (int i = low; i <= hight; i++) //将 b 数组的值传递给数组 a
{
a[i] = b[k++];
}
delete[]b; // 辅助数组用完后,将其的空间进行释放(销毁)
}
/*
* 归并排序
*/
void mergesort(int* a, int low, int hight) //归并排序
{
//或者 if (x>=y) return; 因为如果low==0,high==1 mid+1就会出现low>high的情况
if (low >= hight) return;
int mid = (low + hight) / 2;
mergesort(a, low, mid); //对 a[low,mid]进行分隔
mergesort(a, mid + 1, hight); //对 a[mid+1,hight]进行分割
merge(a, low, mid, hight); //进行合并操作
}
int main()
{
//8, 2, 21, 34, 12, 32, 6, 16, 11, 5
int a[] = { 8, 2, 21, 34, 12, 32, 6, 16, 11, 5 };
int n = 10;
//cout << "请输入数列中的元素个数 n 为:" << endl;
//cin >> n;
//cout << "请依次输入数列中的元素:" << endl;
//for (int i = 0; i < n; i++)
//{
// cin >> a[i];
//}
cout << "归并排序过程" << endl;
mergesort(a, 0, n - 1);
cout << "归并排序结果" << endl;
for (int i = 0; i < n; i++)
{
cout << a[i] << " ";
}
cout << endl;
return 0;
}
6、教材P397题11:实现英文单词按字典序排列的基数排序算法(备选题,可以不做)
编写一个程序exp10-11.cpp,采用基数排序方法将一组英文单词按字典序排列。假设单词均由小写字母或空格构成,最长的单词MaxLen个字母,用相关数据进行测试并输出各趟的排序结果。