数据结构与算法笔记8-查找


参考《大话数据结构》

静态查找

1. 顺序表查找

从头到尾逐个遍历

int Sequential(int *a, int n, int key)
{
	a[0] = key;	//设置哨兵
	int i=n;
	while(a[i] != key)
	{
		i--;
	}
	return i;	//若返回 0,则说明查找失败
}

2.有序表查找

这类算法要求有序查找表

2.1 折半查找算法

int Binary_search(int *a, int n, int key)
{
	int high = n;
	int low = 1;	//这里定义从1位置开始查找
	int mid = 0;
	while(high >= low)
	{
		mid = (high + low)/2;
		if(a[mid] > key)
			low = mid+1;
		else if(a[mid < key])
			high = mid - 1;
		else
			return mid;
	}
	return 0;
}

2.2 插值查找算法

对折半查找的改进,主要的改进点在分割点上:
在这里插入图片描述

int Insert_search(int *a, int n, int key)
{
	int high = n;
	int low = 1;	//这里定义从1位置开始查找
	int mid = 0;
	while(high >= low)
	{
		mid = low + (high-low)*(key-a[low])/(a[high]-a[low]);	//仅这里改进一处
		if(a[mid] > key)
			low = mid+1;
		else if(a[mid < key])
			high = mid - 1;
		else
			return mid;
	}
	return 0;
}

2.3 斐波那契查找算法

这个算法是使用黄金分割点来“折半查找”,其实也是分割点的不同。
菲波那切数列在这里仅仅是用作分割点,而我们查找的查找表可以是满足有序的任意表。
在这里插入图片描述
在这里插入图片描述

//假设我们已经定义了一个斐波那切数列 *F,如上图
int Fibonacci_Search(int *a, int n, int key)
{
	int low,high,mid,i,k;
	int high = n;
	int low = 1;
	k = 0;
	while(n > F[k]-1)		//计算n位于菲波那切数列的位置
		k++;				//因为想要用菲波那切数列做分割点,所以需要和查找表长度n比较
	for(i=n; i<F[k]-1;i++)	//将不满的数值补全
		a[i] = a[n];		//即构造与菲波那切数列相匹配的查找表
	while(low<=high)		
	{
		mid=low+F[k-1]-1;	//计算当前分隔符下标,此为分割点
		if(key < a[mid])
		{
			high=mid-1;
			k = k-1;		//控制数据范围
		}
		else if (key > a[mid])
		{
			low = low+1;
			k = k-2;		//控制数据范围
		}
		else
		{
			if(mid<=n)
				return mid;
			else
				return n;	//若mid>n说明是不全数值,返回0
		}
	}
}

在这里插入图片描述
在这里插入图片描述

3.线性索引查找

3.1 稠密索引

在这里插入图片描述

3.2 分块索引

原则:块间有序,快内无序
在这里插入图片描述

3.3 倒排索引

在这里插入图片描述

动态查找

4.二叉排序树

4.1 二叉排序树的定义:

在这里插入图片描述
实际上二叉排序树不一定是上图所示的满二叉树。

在这里插入图片描述
在这里插入图片描述

4.2 二叉排序树查找

//构造二叉排序树的数据结构
typedef struct BiTNode
{
	int data;
	struct BiTNode *lrchild, *rchaild;
}BiTNode, *BiTree;

//算法主体
//指针 f 指向 T 的双亲,初始值为Null
//若查找成功,则指针p指向该数据元素结点
//否则指针p指向查找路径上访问的最后一个结点
int BiTree_Search(BiTree T, int key, BiTree f, BiTree *p)
{
		if(!T)			//	查找不成功
		{
			*p = f;
			return FALSE;
		}
		else if (key == T->data)	//查找成功
		{
			*p = T;
			return TRUE;
		}
		else if (key < T->data)
			return SearchBST(T->lchild, key, T, p);	//此时T (f)为T->lchild (T)的双亲
		else
			return SearchBST(T->rchild, key, T, p);
}

4.2 二叉排序树插入

//当T中不存在关键字k时,插入key并返回True,否则返回FALSE
int InsertBST(BiTree *T, int key)
{
	BiTree p,s;
	if( !SearchBST(*T, key, NULL, &p))	//查找不成功
	{
		s = (BiTree)malloc(sizeof(BiTNode));
		s->data = key;
		s->lchild = s->rchild = NULL;
		if(!p)			//p 是遍历了整棵树的指针,若树空则为 p 为空;若树非空,则 p 指向最后一个访问的结点,不为空;
			(*T)=s;		//插入新的根节点
		else if (key < p->data)	//??若不是插在叶子节点呢?或者插在叶子结点不能保证其仍是二叉排序树呢????
			p->lchild = s;
		else
			p->rchild = s;
		return TRUE;
	}
	else
		return FALSE;
}

4.2 二叉排序树删除

int DeleteBST(BiTree *T, int key)
{
	if(!*T)
		return FALSE;
	else
	{
		if(key == (*T)->data)
			return Delete(T);
		else if(key<(*T)->data)
			return DeleteBST(&(*T)->lchild, key);
		else
			return DeleteBST(&(*T)->rchild, key);
	}
}

int Delete(BiTree *p)
{
	BiTree q,s;
	if( (*p)->rchild == NULL)			//右子树空则只需要重接它的左子树
	{
		q = *p; *p=(*p)->lchild; free(q);
	}
	else if((*p)->lchild==NULL)			//只需要重接它的右子树
	{
		q = *p; *p=(*p)->rchild; free(q);
	}
	else
	{
		q=*p; s = (*p)->lchild;
		while(s->rchild)		//转左,然后向右到尽头(找到待删除结点的前驱)
		{
			q=s;s=s->rchild;
		}
		(*p)->data = s->data;	// s 指向被删除结点的直接前驱
		if(q!=p)					//这是也说明待删除的p有右结点
			q->rchild=s->lchild;	//重接q的右子树	
		else
			q->lchild=s->lchild;	//重接q的左子树
		free(s);
	}
	return TRUE;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值