数据结构(C语言版)-6.查找

1. 查找的基本概念

2. 静态查找

2.1 顺序查找

c 复制代码
typedef int KeyType;
typedef int InfoType;
typedef struct
{
	KeyType key;
	InfoType otherdata;
}SeqList; // 顺序表类型
// 顺序查找
c 复制代码
int SeqSearch(SeqList R[], int n, int k)
{
	int i = n;
	R[0].key = k;  // R[0].key为查找不成功的监视哨
	while (R[i].key != k)
		i--;
	return i; // 查找成功返回所找元素的索引,否则返回0;
}

2.2 有序表的查找

二分查找

c 复制代码
int BinarySearch(SeqList R[], int n, int k)
{
	int left = 0, right = n - 1;
	int mid = 0;
	while (left <= right)
	{
		mid = (left + right) / 2;
		if (R[mid].key > k)
			right = mid - 1;
		else if (R[mid].key < k)
			left = mid + 1;
		else
			return mid;
	}
	return 0;// 没有找到
}

分块查找(索引顺序查找)

3. 树表形式的动态查找表

3.1 二叉排序树

二叉排序树的查找操作

c 复制代码
// 二叉排序树的查找操作
BSTree* BSTSearch(BSTree* t, int k)
{
	while (t != NULL)
	{
		if (t->key > k)
			t = t->lchild;
		else if (t->key < k)
			t = t->rchild;
		else
			return t;
	}
	return NULL;
}

二叉排序树的插入操作和二叉树排序树的构造

  • 愚蠢的bug,直接拿着main函数传入的指针遍历二叉排序树,导致每次插入节点时都会丢失二叉排序树的根
c 复制代码
void BSTCreate(BSTree** t, int k)
{
	BSTree* pre = NULL;
	while ((*t) != NULL)
	{
		if ((*t)->key > k) {
			pre = *t;
			*t = (*t)->lchild;
		}
		else if ((*t)->key < k) {
			printf("______________,右子树\n");
			pre = *t;
			*t = (*t)->rchild;
		}
		else  // 所查节点已经存在
			break;
	} 
	
	//当所查节点不存在时
	if (*t == NULL)
	{
		
		BSTree* tmp = (BSTree*)malloc(sizeof(BSTree));
		tmp->lchild = NULL;
		tmp->rchild = NULL;
		tmp->key = k;
		if (pre != NULL) {
			if (pre->key > k) {  // 应该插入pre的左孩子
				pre->lchild = tmp;
			}
			else { // 应该插入pre的右孩子
				printf("应该插入pre的右孩子\n");
				pre->rchild = tmp;
			}
		}
		else { // 二叉排序树还未建立
			printf("建立二叉排序树\n");
			*t = tmp;
		}
	}
		
}
  • 正确的方式
c 复制代码
void BSTCreate(BSTree** t, int k)
{
	
	BSTree* pre = NULL,*current = *t;
	while (current != NULL)
	{
		if (current->key > k) {
			pre = current;
			current = current->lchild;
		}
		else if (current->key < k) {
		/*	printf("______________,右子树\n");*/
			pre = current;
			current = current->rchild;
		}
		else  // 所查节点已经存在
			return;
	} 
		BSTree* tmp = (BSTree*)malloc(sizeof(BSTree));
		tmp->lchild = NULL;
		tmp->rchild = NULL;
		tmp->key = k;
		if (pre != NULL) {
			if (pre->key > k) {  // 应该插入pre的左孩子
				pre->lchild = tmp;
			}
			else { // 应该插入pre的右孩子
				//printf("应该插入pre的右孩子\n");
				pre->rchild = tmp;
			}
		}
		// 二叉排序树还未建立
		else { 
			printf("建立二叉排序树\n");
			*t = tmp;
		}
		
}


删除二叉排序树中的节点


c 复制代码
void BSTDeleteLeafChild(BSTree* pre, BSTree* current)
{
	if (pre->lchild == current) // 待删除节点为pre的左孩子
	{
		pre->lchild = NULL;
	}
	else if (pre->rchild == current) {
		pre->rchild = NULL;
	}
	free(current);
	current = NULL;
}
void BSTDeleteRightChild(BSTree* pre, BSTree* current)
{
	// 待删除节点current只有右孩子,直接将该有孩子替换到待删除节点位置即可
	if (pre->lchild == current) // 待删除节点为pre的左孩子
	{
		pre->lchild = current->rchild;
		free(current);
		current = NULL;
	}
	else if (pre->rchild == current) {
		pre->rchild = current->rchild;
		free(current);
		current = NULL;
	}
	else {
		printf("BSTDeleteRightChild:pre和current没有父子关系!!!\n");
	}

}
void BSTDeleteLeftChild(BSTree* pre, BSTree* current)
{
	// 待删除节点current只有左孩子,直接将该左孩子替换到待删除节点位置即可
	if (pre->lchild == current) // 待删除节点为pre的左孩子
	{
		pre->lchild = current->lchild;
		free(current);
		current = NULL;
	}
	else if (pre->rchild == current) {
		pre->rchild = current->lchild;
		free(current);
		current = NULL;
	}
	else {
		printf("BSTDeleteRightChild:pre和current没有父子关系!!!\n");
	}
}
// 在二叉排序树种删除某个节点
void BSTDelete(BSTree** t, int k)
{
	/*
		会出现四种情况
		1. 待删除的节点为叶子
		2. 待删除的节点只有左孩子
		3. 待删除节点只有右孩子
		4. 待删除节点左右孩子都有
	*/
	BSTree* pre = NULL, * current = *t;
	while (current != NULL)
	{
		if (current->key > k) {
			pre = current;
			current = current->lchild;
		}
		else if (current->key < k) {
			pre = current;
			current = current->rchild;
		}
		else  // 节点找到
			break;
	}
	if (current == NULL)
	{
		printf("该节点没有找到\n");
		return;
	}
	//1. 待删除的节点为叶子
	if (current->lchild == NULL && current->rchild == NULL)
	{
		BSTDeleteLeafChild(pre, current);
	}
	//2. 待删除的节点只有左孩子
	else if (current->lchild != NULL && current->rchild == NULL)
	{
		BSTDeleteLeftChild(pre, current);
	}
	//3. 待删除节点只有右孩子
	else if (current->lchild == NULL && current->rchild != NULL)
	{
		BSTDeleteRightChild(pre,current);
	}
	//4. 待删除节点左右孩子都有
	else  
	{
		// 1. 首先找到以待删除节点为根的最左节点
		BSTree* t1 = current,*t2 = current;
		while (t2->lchild != NULL)
		{
			t1 = t2;
			t2 = t2->lchild;
		}
		current->key = t2->key;
		 2. 删除最左节点
		if(t2->rchild!=NULL)
			BSTDeleteRightChild(t1, t2);
		else {
			t1->lchild = NULL;
			free(t2);
			t2 = NULL;
		}
	}
}

3.2 平衡二叉树(AVL)



红黑树

红黑树





3.3 B树和B+树




B树



B树的插入


  • 例子



  • 例子
  • 插入15
  • 插入35
  • 插入95
B树的删除

  • 例子


  • 删除92

  • 删除80

    • 删除70

B+树





两者的区别

区别

4. 哈希

4.1 哈希表与哈希方法

4.2 哈希函数

直接定址法

除留余数法

数字分析法

平方取中法

折叠法

4.3 处理冲突的方法

闭散列表

开放地址法
再散列法

开散列表

4.4 哈希表的查找

练习题

相关推荐
乐悠小码9 分钟前
Java设计模式精讲---02抽象工厂模式
java·设计模式·抽象工厂模式
数据的世界0111 分钟前
技术变革:为何C#与.NET是未来的开发方向
java·c#·.net
向上的车轮18 分钟前
Actix Web适合什么类型的Web应用?可以部署 Java 或 .NET 的应用程序?
java·前端·rust·.net
脸大是真的好~27 分钟前
黑马JAVAWeb-03 SpringBootWeb-分层解耦-三层架构-@SpringBootApplication注解-IOC控制反转-DI依赖注入
java
微露清风40 分钟前
系统性学习C++-第十讲-stack 和 quene
java·c++·学习
抠脚学代码40 分钟前
Linux开发-->驱动开发-->字符设备驱动框架
linux·数据结构·驱动开发
一蓑烟雨任平生√44 分钟前
两种上传图片的方式——91张先生
java·ossinsight
是苏浙1 小时前
零基础入门C语言之枚举和联合体
c语言·开发语言
凤凰战士芭比Q1 小时前
部署我的世界-java版服务器-frp内网穿透
java·服务器
小肖爱笑不爱笑1 小时前
2025/11/5 IO流(字节流、字符流、字节缓冲流、字符缓冲流) 计算机存储规则(ASCII、GBK、Unicode)
java·开发语言·算法