数据结构学习笔记(第七章 查找)

目录

基本概念

静态查找:

动态查找:

线性结构

顺序查找

折半查找

分块查找

主要思想

树形结构

二叉排序树(BST)

核心思想:

 代码示例

平衡二叉树

性质:

 平衡因子计算:

平衡树调整最小不平衡子树

 删除操作简介

红黑树(较为复杂)

基本介绍

 插入简介(王道书278页)​编辑

B树及B+树

基本介绍

 B+:

区别:

散列表

散列函数的构造方法

处理冲突的方法 


基本概念

静态查找:

在静态查找表上进行的查找操作,查找满足条件的数据元素的储存位置或者各种属性。

静态查找有三种查找方式:顺序查找、折半查找和散列查找。

动态查找:

需动态的插入或删除的查找表。

查找方式有:二叉排序树查找和散列查找,二叉排序树和B树都是二叉排序树的改进。

线性结构

顺序查找

顺序查找又称线性查找,顾名思义,就是按顺序依次查找元素。对顺序表和链表都适用。

typedef int ElemType;
typedef struct{
	ElemType *elem;//整形指针
	int TableLen; //存储动态数组元素个数 
}SSTable;

int Search_Seq(SSTable ST,ElemType key){
	ST.elem[0]=key;//作为哨兵 
	int i;
	for(i=ST.TableLen-1;ST.elem[i]!=key;--i);
	return i;
}

折半查找

又称二分查找,仅适用于有序顺序表。顾名思义,每次查找都拿中间元素比较。

int Binary_Search(SSTable L,ElemType key){
	int low=0,high=L.TableLen-1,mid;
	while(low<=high){
		mid=(low+high)/2;
		if(L.elem[mid]==key){
			return mid;
		}
		else if(L.elem[mid]>key){
			high=mid-1;
		}else{
			low=mid+1;
		}
	}
	return -1;
}

分块查找

又称索引顺序查找,吸收了顺序查找和折半查找的优点,既有动态结构,又适用于快速查找。

主要思想

将查找表分为若干块,块内元素可以无序,但块之间是有序的,即第一块最大的关键字(元素)小于第二个块中所有关键字。在建立一个索引表,索引表中包括各块最大关键字和各块第一个元素地址,索引表按关键字有序排列。

查找过程:第一步查找所在块,可以顺序或折半查找索引表。第二步在块内顺序查找。

树形结构

二叉排序树(BST)

又称二叉查找树。

核心思想

左子树值<根节点值<右子树值,所以对其进行中序遍历,可以得到递增有序序列。1 2 3 4 6 8

图解:什么是二叉排序树?_吴师兄学算法的博客-CSDN博客 

 代码示例

//结构定义 
typedef int KeyType;
typedef struct BSTNode{
	KeyType key;
	struct BSTNode *lchild,*rchild;
}BSTNode,*BiTree;

//插入 
int BST_Insert(BiTree &T,KeyType k){
	if(T==NULL){
		T=(BiTree)malloc(sizeof(BSTNode));
		T->key=k;
		T->lchild=T->rchild=NULL;
		return 1;//插入成功 
	}
	else if(k==T->key){
		return 0;//发现相同元素,不插入 
	}
	else if(k<T->key){
		return BST_Insert(T->lchild,k);
	}
	else{
		return BST_Insert(T->rchild,k);
	}
	
}
//建表 
void Create_BST(BiTree &T,KeyType str[],int n){
	T=NULL;
	int i=0;
	while(i<n){
		BST_Insert(T,str[i]);
		i++;
	}
}
//中序 
void InOrder(BiTree T){
	if(T!=NULL){
		InOrder(T->lchild);
		printf("%3d",T->key);
		InOrder(T->rchild);
	}
}
//查找 
BSTNode *BST_Search(BiTree T,KeyType key,BiTree &p){
	p=NULL;
	while(T!=NULL&&key!=T->key){
		p=T;
		if(key<T->key)
			T=T->lchild;//比当前结点小,往左找
		else
			T=T->rchild;//反之往右 
	}
	return T; 
}
//删除 
void DeleteNode(BiTree &root,KeyType x){
	if(root==NULL){
		return;
	}
	if(root->key>x){
		DeleteNode(root->lchild,x);
	}else if(root->key<x){
		DeleteNode(root->rchild,x);
	}else{//找到了 
		if(root->lchild==NULL){//左子树为空 
			BiTree tempNode=root;
			root=root->rchild;
			free(tempNode);
		}else if(root->rchild==NULL){//右子树为空 
			BiTree tempNode=root;
			root=root->lchild;
			free(tempNode);
		}else{//左右子树非空 
			BiTree tempNode=root->lchild;
			if(tempNode->rchild!=NULL){
				tempNode=tempNode->rchild;
			}
			root->key=tempNode->key;
			DeleteNode(root->lchild,tempNode->key);
		}
	}
} 

平衡二叉树

简称平衡树。

性质

1.是二叉排序树

2.左右子树高度差绝对值不超过1。因此平衡因子BF(Balance Factor )可能为-1,0,1。

 平衡因子计算

左子树深度减右子树深度。

平衡树调整最小不平衡子树

一旦平衡因子绝对值大于一,平衡树失衡,需要通过旋转来调整。

 插入一个新结点,很可能导致平衡树不再平衡,这时候我们需要对其进行调整。大致分为四种情况。

旋转方式:

  1. 左旋
    • 旧根节点为新根节点的左子树
    • 新根节点的左子树(如果存在)为旧根节点的右子树
  2. 右旋:
    • 旧根节点为新根节点的右子树
    • 新根节点的右子树(如果存在)为旧根节点的左子树

1.LL(右单旋转),在A结点的左孩子的左子树上插入新结点。

 2.RR(左单旋转),在A的右孩子的右子树上插入新结点。

 3.LR(先左后右双旋转),在A的左孩子的右子树上插入新节点。

 4.RL(先右后左双旋转),在A的右孩子的左子树上插入新结点。

 删除操作简介

平衡二叉树详解 通俗易懂_邓嘉文Jarvan的博客-CSDN博客_平衡二叉树

红黑树(较为复杂)

基本介绍

红黑树是一种自平衡的二叉查找树。

 从某结点出发(不含该结点)到达一个叶结点的简单路径上的黑结点总数称为该结点的黑高(bh)根节点的黑高称为红黑树的黑高。

结论1:从根结点到叶结点的最长路径不大于最短路径的二倍。

从根结点到任一叶结点的简单路径最短时,这条路径必然全由黑结点构成。当某条路径最长时,这条路径必然是由黑结点和红结点相间构成的,且红黑结点数量相等。

结论2:有n个内部节点的红黑树高度h<=2log2(n+1).

结论3:新插入结点颜色初始为红色,随后再调整。

 插入简介(王道书278页)

 这里的3种情况有点复杂,下面这个写的比较清楚

红黑树的插入和删除_weixin_52696654的博客-CSDN博客_红黑树的插入删除

漫画:什么是红黑树?(整合版)_程序员小灰的博客-CSDN博客

B树及B+树

基本介绍

 示例:

 B+:

区别:

B树和B+树_ZJE_ANDY的博客-CSDN博客_b树的阶数

散列表

散列函数:一个把查找表中的关键字映射成该关键字对应的地址函数,记为Hash(key)=Addr,这里地址可以是数组下标,索引或内存地址。

冲突:把两种或两种以上不同关键字映射到同一地址。

同义词:发生碰撞的不同关键字。

散列表:根据关键字而直接访问的数据结构。(散列表建立了关键字和存储地址之间的直接映射关系)

散列函数的构造方法

1.直接定址法

H(key)=key或H(key)=a*key+b,a和b为常数

2.除数留余法

H(key)=key%p,p为不大于表长但最接近表长的质数

3.数字分析法

4.平方取中法

处理冲突的方法 

1.开放定址法

 其中增量取法有四种,分别为线性探测法,平方探测法,双散列法和伪随机序列法。

详细增量取法请看下面的链接,写的比较详细。

散列表(开放定址法)_时代&信念的博客-CSDN博客_开放定址法

2.拉链法

 下面是一个示例代码,仅供参考。

int hash(const char* key)
{
	int h = 0, g;
	while (*key)
	{
		h = (h << 4) + *key++;
		g = h & 0xf0000000;
		if (g)
		{
			h ^= g >> 24;
		}
		h &= ~g;
	}
	return h % MaxKey;//算出下标要取余
}

int main()
{
	const char* pStr[5] = { "xiongda","lele","hanmeimei","wangdao","fenghua" };
	int i;
	const char* pHash_table[MaxKey] = {NULL};//哈希表,散列表
	for (i = 0; i < 5; i++)
	{
		printf("%s is key=%d\n", pStr[i], hash(pStr[i]));//算哈希值并打印
		pHash_table[hash(pStr[i])] = pStr[i];//存入哈希表
	}
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

低调$(生活)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值