数据结构实验四 : 查找和排序算法实现

数据结构实验一:线性表,堆栈和队列实现
数据结构实验二 :二叉树的操作与实现
数据结构实验三: 图的操作与实现
数据结构实验四 : 查找和排序算法实现

一、实验目的:

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个字母,用相关数据进行测试并输出各趟的排序结果。

  • 1
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值