二叉查找树(BST)和折半查找(C语言实现)

目录

实验要求

一、生成数据

二、构建二叉查找树

三、删除操作

四、插入操作

五、查找操作

六、折半查找

七、二叉查找树和折半查找的时间性能

(1)斜树的时间性能

(2)正常二叉树的时间性能

(3)折半查找的时间性能

(4)总结

代码实现:


实验要求

一、生成数据

1.生成0-2048的奇数作为顺序序列,存放到Seq.txt

2.将这些奇数打乱顺序,存放到Random.txt

1 顺序序列

2:随机序列

二、构建二叉查找树

读取两个文件,分别常见二叉查找树T1,T2。其中,

T1是顺序序列得到的,是一棵斜树

T2是随机序列得到的,是正常的二叉查找树

三、删除操作

指定特定的元素进行删除

中序遍历删除后的二叉查找树进行展示

3:删除操作

四、插入操作

指定元素,插入到二叉查找树中,

中序遍历树,进行结果展示

4:插入操作

五、查找操作

5:查找成功

6:查找失败

六、折半查找

7:折半查找成功

8:折半查找失败

七、二叉查找树和折半查找的时间性能

9:二叉查找树和折半查找的时间性能

(1)斜树的时间性能

如果数组是按顺序存储段,那么斜二叉查找树实际就是退化为链式存储,和单链表的顺序查找的时间性能是一样的,为n+1)/ 2

本实验中n是1024,所以平均比较次数为512.5左右。

(2)正常二叉树的时间性能

如果数据的序列是随机的,则正常二叉查找树和折半查找的判定树类似,为O(log2n

本实验中的n是1024,所以平均比较次数为10左右。

(3)折半查找的时间性能

当n很大时,折半查找的查找成功的平均查找长度约为log2(n+1)-1

查找失败和查找最坏情况的关键字比较次数不超过判定树的高度log2[n+1]的上取整

本实验中的n是1024,所以平均比较次数为10左右。

(4)总结

当数据是有序的时候,二叉查找树的时间性能差。

当数据是随机的时候,二叉查找树和折半查找性能类似的。

在平均情况下,二叉查找树的查找和折半查找差不多,都是O(log2n级别的。

就维护表的有序性而言,二叉查找树更有效。

代码实现

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include <time.h>
#define ArraySize 1024				//数组的大小
#define UpLimit 2048				//数组数字的上界
typedef int records;
typedef struct celltype				//二叉查找树的节点,左右链存储
{
	records data;					//关键字
	struct celltype* lchild;		//左孩子
	struct celltype* rchild;		//右孩子
}BSTNode;
typedef BSTNode* BST;
typedef records* List;
int BSTcount = 0;					//中序遍历二叉查找树时的数组下标
int count = 0;						//查找次数
void Insert(BST *T, records k);
BSTNode* Search(BST T, records k);
records DeleteMin(BST *T);
void Delete(BST *T, records k);
void Inorder(BST T, List L);
int BinSearch(List L,records k,int up);
void GenerateData(void);
void PrintData(char* filename);
BST CreateBST(char* filename);
void ASL_BST(BST T);
void ASL_BinSearch(List number);
void Delete_packed(BST* T,records *number);
void Insert_packed(BST* T, records* number);
void Search_packed(BST T);
void BinSearch_packed(records* number);

int main(void)
{
	printf("生成数据:\n");
	GenerateData();
	printf("0-2048的奇数顺序排列\n");
	PrintData("Seq.txt");
	printf("\n0-2048的奇数随机排列\n");
	PrintData("Random.txt");
	BST T1 = CreateBST("Seq.txt");
	BST T2 = CreateBST("Random.txt");
	printf("\n\n斜二叉查找树(T1)的平均查找长度:\n");
	ASL_BST(T1);
	printf("\n正常二叉查找树(T2)的平均查找长度:\n");
	ASL_BST(T2);
	printf("\n中序遍历二叉查找树进行排序,输出给需要折半查找的数组\n");
	records number[ArraySize] = { 0 };
	BSTcount = 0;
	Inorder(T2, number);
	printf("折半查找的平均查找长度:\n");
	ASL_BinSearch(number);

	Delete_packed(&T2,number);
	Insert_packed(&T2, number);
	Search_packed(T2);
	BinSearch_packed(number);
	return 0;
}

//向二叉查找树插入
//修改一级指针是需要使用二级指针
void Insert(BST *T, records k)
{
	if (*T == NULL)				//创建新节点
	{
		BSTNode *p = (BSTNode*)malloc(sizeof(BSTNode));
		if (p == NULL)	return;
		p->data = k;
		p->lchild = p->rchild = NULL;
		*T = p;
	}
	else if ((*T)->data == k)	return;
	else if ((*T)->data > k)	Insert(&((*T)->lchild), k);
	else if ((*T)->data < k)	Insert(&((*T)->rchild), k);
}



//二叉查找树的查找
BSTNode* Search(BST T, records k)
{
	BSTNode* p = T;
	if (p==NULL)		//空树,递归中止
	{
		return p;
	}
	count++;			//比较次数计数
	if (p->data == k)
	{
		return p;
	}
	else if (k < p->data)
	{
		return Search(p->lchild, k);	//查找左子树
	}
	else if (k > p->data)
	{
		return Search(p->rchild, k);	//查找右子树
	}
}

//删除T的最小节点
records DeleteMin(BST *T)
{
	records temp;
	BST p;
	if ((*T)->lchild == NULL)		//是最小元
	{
		p = *T;
		temp = (*T)->data;
		*T = (*T)->rchild;			//右链继承
		free(p);
		return temp;
	}
	else			//左子树不空,则最小元在左子树上
	{
		return DeleteMin(&((*T)->lchild));
	}
}

//删除关键字为k的节点
void Delete(BST *T, records k)
{
	if ((*T) != NULL)
	{
		if (k <  (*T)->data)			//递归地到左子树中去删除
		{
			Delete(&((*T)->lchild), k);
		}
		else if (k > (*T)->data)		//递归地到右子树中去删除
		{
			Delete(&((*T)->rchild), k);
		}
		else
		{
			if ((*T)->lchild == NULL)	*T = (*T)->rchild;		//右链继承
			else if ((*T)->rchild == NULL)	*T = (*T)->lchild;	//左链继承
			else	(* T)->data = DeleteMin(&((*T)->rchild));		//左右子树非空,则用右子树的最左节点代替
		}
	}
}

//对二叉查找树中序遍历,即可实现排序
//可以将排好序的数组输出给折半查找
void Inorder(BST T, List L)
{
	if (T == NULL)	return;
	Inorder(T->lchild, L);
	L[BSTcount] = T->data;
	BSTcount++;
	Inorder(T->rchild, L);
}

//折半查找(非递归)
int BinSearch(List L, records k,int up)
{
	int low = 0;
	int mid;
	while (low <= up)
	{
		mid = (low + up) / 2;
		count++;		//比较次数加1
		if (L[mid] == k)	return mid;
		else if (L[mid] > k)	up = mid - 1;
		else if (L[mid] < k)	low = mid + 1;
	}
	return -1;
}

//生成顺序和随机序列,分别写入Seq.txt Random.txt
void GenerateData(void)
{
	FILE* fp1,*fp2;		//文件指针
	int array[ArraySize], temp;
	fp1 = fopen("Seq.txt", "w");
	fp2 = fopen("Random.txt", "w");
	if (!fp1 || !fp2)
	{
		printf("文件打开失败\n");
		return;
	}
	
	for (int i = 0;i < ArraySize;++i)	//顺序数组,写入Seq.txt
	{
		array[i] = 2 * i + 1;
		fprintf(fp1, "%d ", array[i]);
	}
	fclose(fp1);
	
	srand(time(0));
	int randomidx;						//随机下标,用来打乱数组的顺序
	for (int i = 0;i < ArraySize;++i)	//通过交换实现序列的随机化
	{
		randomidx = rand() % ArraySize;
		temp = array[i];
		array[i] = array[randomidx];
		array[randomidx] = temp;
	}
	for (int i = 0;i < ArraySize;++i)	//乱序数组,写入Random.txt
	{
		fprintf(fp2, "%d ", array[i]);
	}
	fclose(fp2);
}

//打印数据
void PrintData(char* filename)
{
	FILE* fp = fopen(filename, "r");
	if (fp == NULL)	return;
	records k;
	for (int i = 0;i < ArraySize;++i)
	{
		fscanf(fp, "%d ", &k);
		printf("%d ", k);
	}
	return;
}

//读取文件创建二叉树
BST CreateBST(char *filename)
{
	//printf("\n二叉查找树如下:\n");
	FILE* fp = fopen(filename, "r");
	if (fp == NULL)	return NULL;
	BST p = NULL;
	records k;		//存储从文件中读出的数字
	for (int i = 0;i < ArraySize;++i)
	{
		fscanf(fp, "%d ", &k);
		Insert(&p, k);
	}
	fclose(fp);
	return p;
}

//二叉查找树的查找成功和查找失败的平均查找长度
//对于本程序的数据集来说:
//查找奇数是查找成功;查找偶数是查找失败
void ASL_BST(BST T)
{
	long sum1 = 0, sum2 = 0;
	BSTNode* p;
	for (int i = 0;i < ArraySize;++i)
	{
		count = 0;
		p = Search(T, 2 * i + 1);
		sum1 += count;
		
	}
	printf("查找成功的平均查找长度(查找奇数)为%f\n", sum1 * (1.0) / ArraySize);
	
	for (int i = 0;i < ArraySize;++i)
	{
		count = 0;
		p = Search(T, 2 * i);
		sum2 += count;
	}
	count = 0;
	p = Search(T, 2048);
	sum2 += count;
	printf("查找失败的平均查找长度(查找偶数)为%f\n", sum2 * (1.0) /(ArraySize+1));

}

//计算折半查找的平均查找长度
void ASL_BinSearch(List number)
{
	long sum1 = 0, sum2 = 0;
	for (int i = 0;i < ArraySize;++i)
	{
		count = 0;
		BinSearch(number, 2 * i + 1, ArraySize - 1);
		sum1 += count;
	}
	printf("查找成功的平均查找长度(查找奇数)为%f\n", sum1 * (1.0) / ArraySize);
	for (int i = 0;i < ArraySize;++i)
	{
		count = 0;
		BinSearch(number, 2 * i, ArraySize - 1);
		sum2 += count;
	}
	printf("查找失败的平均查找长度(查找奇数)为%f\n", sum2 * (1.0) / ArraySize);

}


void Delete_packed(BST* T,records *number)
{
	printf("\n\n从二叉查找树(T2)中删除一个数\n");
	printf("请输入:\t");
	int k;
	scanf("%d", &k);
	Delete(T, k);
	printf("删除后二叉查找树的中序遍历如下\n");
	BSTcount = 0;
	Inorder(*T, number);
	for (int i = 0;i < BSTcount;++i)
	{
		printf("%d ", number[i]);
	}
}

void Insert_packed(BST* T, records* number)
{
	printf("\n\n向二叉查找树中插入一个数\n");
	printf("请输入:\t");
	int k;
	scanf("%d", &k);
	Insert(T, k);
	printf("插入后的二叉查找树的中序遍历如下\n");
	BSTcount = 0;
	Inorder(*T, number);
	for (int i = 0;i < BSTcount;++i)
	{
		printf("%d ", number[i]);
	}
}

void Search_packed(BST T)
{
	printf("\n\n请输入想要在二叉查找树中查找的值\n");
	int k;
	scanf("%d", &k);
	count = 0;
	BSTNode* p = Search(T, k);
	if (p)
	{
		printf("查找成功,查找次数为%d\n",count);
	}
	else	printf("查找失败\n");
}

void BinSearch_packed(records* number)
{
	printf("\n\n请输入需要折半查找的值\n");
	int k;
	scanf("%d", &k);
	count = 0;
	int result  = BinSearch(number,k,BSTcount-1);
	if (result == -1)	printf("查找失败\n");
	else
	{
		printf("查找成功,查找次数为%d\n",count);
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值