查找

目录

静态查找

二叉排序树

平衡二叉树——AVL树


静态查找

1. 顺序表查找

2. 二分查找

3. 插值查找

    核心公式:mid = low + (high - low) * (key - a[low]) / (a[high] - a[low]);

4. 斐波那契查找

    斐波那契查找与折半查找很相似,他是根据斐波那契序列的特点对有序表进行分割的。他要求开始表中记录的个数为某个斐波那契数小1,及n=F(k)-1;开始将k值与第F(k-1)位置的记录进行比较(及mid=low+F(k-1)-1),比较结果也分为三种:

(1)相等,则mid位置的元素即为所求;

(2)>,则low=mid+1,k-=2;

说明:low=mid+1说明待查找的元素在[mid+1,high]范围内,k-=2 说明范围[mid+1,high]内的元素个数为n-(F(k-1))=Fk-1-F(k-1)=Fk-F(k-1)-1=F(k-2)-1个,所以可以递归的应用斐波那契查找。

(3)<,则high=mid-1,k-=1。

说明:low=mid+1说明待查找的元素在[low,mid-1]范围内,k-=1 说明范围[low,mid-1]内的元素个数为F(k-1)-1个,所以可以递归的应用斐波那契查找。

#include <stdio.h>

#define MAXSIZE 100

// 顺序表查找 
int Sequential_Search(int * a, int len, int key)
{
	for (int i = 0; i <= len; i++) {
		if (a[i] == key) {
			return i;
		}
	}	
	return -1;
} 
// 二分查找 
int Binary_Search(int * a, int len, int key)
{
	int low, high, mid;
	low = 0;
	high = len;
	while (low <= high) {
		mid = (low + high) / 2;
		if (key < a[mid]) {
			high = mid - 1;
		} else if (key > a[mid]) {
			low = mid + 1;
		} else {
			return mid;
		}
	}
	return -1;
}
// 插值查找
int Interpolation_Search(int * a, int len, int key)
{
	int low, high, mid;
	low = 0;
	high = len;
	while (low <= high) {
		mid = low + (high - low) * (key - a[low]) / (a[high] - a[low]);	// 插值 
		//printf("key=%d mid=%d a[%d]=%d \n", key, mid, mid, a[mid]);
		if (key < a[mid]) {
			high = mid - 1;
		} else if (key > a[mid]) {
			low = mid + 1;
		} else {
			return mid;
		}
	}
	return -1;	
}
// 斐波那契查找
int Fibonacci_Search(int * a, int len, int key)
{
	int low, high, mid, i, k;
	low = 0;
	high = len;
	k = 0;
	int F[MAXSIZE];
	F[0] = 0;
	F[1] = 1;
	for (i = 2; i <= MAXSIZE; i++) {	// 生成斐波那契数列 
		F[i] = F[i - 1] + F[i - 2];
	}
	
	while (len > F[k] - 1) {
		k++;
	}
	for (i = len; i < F[k] - 1; i++) {
		a[i] = a[len];
	}
	
	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 = mid + 1;
			k = k -2;
		} else {
			if (mid <= len) {
				return mid;
			} else {
				return len;
			}
		}
	}
	return -1;
}

int main()
{
	int a[MAXSIZE];
	printf("数组a为0-100有序表\n");
	for (int i = 0; i <= MAXSIZE - 1; i++) {
		a[i] = i; 
	}
	int arr[10] = {0, 2, 15, 24, 33, 38, 55, 84, 88, 99};
	printf("数组arr为");
	for (int i = 0; i < 10; i++) {
		printf("%d ", arr[i]);
	}
	
	printf("\n请输入要查找的数字:");
	int key;
	scanf("%d", &key);
	int res = Sequential_Search(a, MAXSIZE, key);
	printf("顺序表查找%d在数组a中的位置为:%d\n", key, res);
	res = Binary_Search(a, MAXSIZE, key);
	printf("二分查找%d在数组a中的位置为:%d\n", key, res);
	
	
	res = Interpolation_Search(a, MAXSIZE - 1, key);
	printf("插值查找%d在数组a中的位置为:%d\n", key, res);
	
	
	res = Fibonacci_Search(arr, 10, key);
	printf("斐波那契查找%d在数组arr中的位置为:%d\n", key, res);
}

二叉排序树

 

#include <stdio.h>
#include <stdlib.h>

typedef struct BiTNode	// 结点结构 
{
	int data;			// 结点数据 
	struct BiTNode * lchild, * rchild;	// 左右孩子指针 
}BiTNode, * BiTree;

/* 递归查找二叉排序树T中是否存在key, 
   指针f指向T的双亲,其初始调用值为NULL 
   若查找成功,则指针p指向该数据元素结点,并返回TRUE 
   否则指针p指向查找路径上访问的最后一个结点并返回FALSE */
int SearchBST(BiTree T, int key, BiTree f, BiTree * p)
{
	if (!T) {
		*p = f;
		return 0;
	} else if (key == T->data) {
		*p = T;
		return 1;
	} else if (key < T->data) {
		return SearchBST(T->lchild, key, T, p);	// 在左子树中继续查找 
	} else if (key > T->data) {
		return SearchBST(T->rchild, key, T, p);	// 在右子树中继续寻找 
	}
} 
// 插入
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) {
			*T = s;					// 插入s为新的结点 
		} else if (key < p->data){
			p->lchild = s;			// 插入s为左孩子 
		} else if (key > p->data) { 
			p->rchild = s; 			// 插入s为右孩子 
		} 
		return 1;
	} else {
		return 0;		// 树中已有重复key,则不插入 
	}
}
// 删除结点p,并重接它的左或右子树
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;	// s为代删结点左孩子 
		while (s->rchild) {	// 一直寻找s的最右孩子,也就是中序遍历中被删结点的前驱 
			q = s;			
			s = s->rchild; 
		}
		(*p)->data = s->data;
		if (q != *p) {
			q->rchild = s->lchild;
		} else {		// 如果s没有右孩子,则q = *p,就把s左子树接给q 
			q->lchild = s->lchild;
		}
		free(s);
	}
	return 1;
}
// 删除key
int DeleteBST(BiTree * T, int key)
{
	if (!*T) {	// key不在二叉树内 
		return 0;
	} else {
		if (key == (*T)->data) {
			return Delete(T);
		} else if (key < (*T)->data) {
			return DeleteBST(&(*T)->lchild, key);
		} else if (key > (*T)->data){
			return DeleteBST(&(*T)->rchild, key);
		}
	}
} 
// 中递归遍历T
void InOrderTraverse(BiTree T)
{
	if (T == NULL) {
		return;
	}
	InOrderTraverse(T->lchild);	// 中序遍历左子树 
	printf("%d ", T->data);		// 显示结点数据 
	InOrderTraverse(T->rchild);	// 中序遍历后子树 
}
int main()
{
	int a[10] = {62,88,58,47,35,73,51,99,37,93};
	BiTree T = NULL;
	
	for (int i = 0; i < 10; i++) {
		InsertBST(&T, a[i]);
	}
	printf("中序遍历:");
	InOrderTraverse(T);
	DeleteBST(&T,93);
	DeleteBST(&T,47);
	DeleteBST(&T,58);
	printf("\n中序遍历:");
	InOrderTraverse(T);
}

平衡二叉树——AVL树

  • 平衡二叉树(AVL)是一种二叉排序树,其中每一个结点的左子树和右子树的高度差之多为1
  • 将二叉树上结点的左子树深度-右子树深度的值称为平衡因子BF(Balance Factor),BF只能为-1、0、1
  • 距离插入结点最近的,且平衡因子的绝对值大于1的结点为根的子树,我们称为最小不平衡子树

#include <stdio.h>
#include <stdlib.h>

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

#define LH +1	// 左高
#define EH 0	// 登高
#define RH -1	// 右高
 
typedef struct BiTNode	// 结点结构 
{
	int data;	// 结点数据 
	int bf;		// 结点平衡因子 
	struct BiTNode * lchild, * rchild;	// 左右孩子指针 
}BiTNode, * BiTree; 
/* 对以p为根的二叉排序树作右旋处理, */
/* 处理之后p指向新的树根结点,即旋转处理之前的左子树的根结点 */
void R_Rotate(BiTree * P)
{
	BiTree L;
	L = (*P)->lchild;			// L指向P的左子树根结点
	(*P)->lchild = L->rchild; 	// L的右子树挂接为P的左子树 
	L->rchild = (*P);
	*P = L; 					// P指向新的根结点 
}
/* 对以p为根的二叉排序树作左旋处理, */
/* 处理之后p指向新的树根结点,即旋转处理之前的右子树的根结点 */
void L_Rotate(BiTree * P)
{
	BiTree R;
	R = (*P)->rchild;			// R指向P的右子树根结点
	(*P)->rchild = R->lchild; 	//R的左子树挂接为P的右子树 
	R->lchild = (*P);
	*P = R; 					// P指向新的根结点 
}
/*  对以指针T所指结点为根的二叉树作左平衡旋转处理 */
/*  本算法结束时,指针T指向新的根结点 */
void LeftBalance(BiTree * T)
{
	BiTree L, Lr;
	L = (*T)->lchild;
	switch(L->bf) {
		// 检查T的左子树的平衡度,并作相应平衡处理  
		case LH:	// 新结点插入在T的左孩子的左子树上,要作单右旋处理 
			(*T)->bf = L->bf = EH;
			R_Rotate(T);
			break;
		case RH:	// 新结点插入在T的左孩子的右子树上,要作双旋处理
			Lr= L->rchild;	// Lr指向T的左孩子的右子树根 
			switch(Lr->bf) {
				//修改T及其左孩子的平衡因子 
				case LH: 
					(*T)->bf = RH;
					L->bf = EH;
					break;
				case EH:
					(*T)->bf = L->bf = EH;
					break;
				case RH:
					(*T)->bf = EH;
					L->bf = LH;
					break;
			} 
			Lr->bf = EH;
			L_Rotate(&(*T)->lchild);	// 对T的左子树作左旋平衡处理 
			R_Rotate(T);				// 对T作右旋平衡处理 
			
	}
}
/*  对以指针T所指结点为根的二叉树作右平衡旋转处理 */
/*  本算法结束时,指针T指向新的根结点 */
void RightBalance(BiTree * T)
{
	BiTree R, Rr;
	R = (*T)->rchild;
	switch(R->bf) {
		// 检查T的右子树的平衡度,并作相应平衡处理  
		case RH:	// 新结点插入在T的右孩子的右子树上,要作单左旋处理 
			(*T)->bf = R->bf = EH;
			L_Rotate(T);
			break;
		case LH:	// 新结点插入在T的右孩子的左子树上,要作双旋处理
			Rr= R->lchild;	// Rr指向T的右孩子的左子树根 
			switch(Rr->bf) {
				//修改T及其右孩子的平衡因子 
				case RH: 
					(*T)->bf = LH;
					R->bf = EH;
					break;
				case EH:
					(*T)->bf = R->bf = EH;
					break;
				case LH:
					(*T)->bf = EH;
					R->bf = RH;
					break;
			} 
			Rr->bf = EH;
			R_Rotate(&(*T)->rchild);	// 对T的左子树作左旋平衡处理 
			L_Rotate(T);				// 对T作右旋平衡处理 
			
	}
}
/*  若在平衡的二叉排序树T中不存在和e有相同关键字的结点,则插入一个 */ 
/*  数据元素为e的新结点,并返回1,否则返回0。若因插入而使二叉排序树 */ 
/*  失去平衡,则作平衡旋转处理,布尔变量taller反映T长高与否。 */
int InsertAVL(BiTree *T,int e,int *taller)
{  
	if(!*T)
	{ /*  插入新结点,树“长高”,置taller为TRUE */ 
		 *T=(BiTree)malloc(sizeof(BiTNode));
		 (*T)->data=e; (*T)->lchild=(*T)->rchild=NULL; (*T)->bf=EH;
		 *taller=1;
	}
	else
	{
		if (e==(*T)->data)
		{ /*  树中已存在和e有相同关键字的结点则不再插入 */ 
			*taller=FALSE; return FALSE;
		}
		if (e<(*T)->data)
		{ /*  应继续在T的左子树中进行搜索 */ 
			if(!InsertAVL(&(*T)->lchild,e,taller)) /*  未插入 */ 
				return FALSE;
			if(*taller) /*   已插入到T的左子树中且左子树“长高” */ 
				switch((*T)->bf) /*  检查T的平衡度 */ 
				{
					case LH: /*  原本左子树比右子树高,需要作左平衡处理 */ 
							LeftBalance(T);	*taller=FALSE; break;
					case EH: /*  原本左、右子树等高,现因左子树增高而使树增高 */ 
							(*T)->bf=LH; *taller=TRUE; break;
					case RH: /*  原本右子树比左子树高,现左、右子树等高 */  
							(*T)->bf=EH; *taller=FALSE; break;
				}
		}
		else
		{ /*  应继续在T的右子树中进行搜索 */ 
			if(!InsertAVL(&(*T)->rchild,e,taller)) /*  未插入 */ 
				return FALSE;
			if(*taller) /*  已插入到T的右子树且右子树“长高” */ 
				switch((*T)->bf) /*  检查T的平衡度 */ 
				{
					case LH: /*  原本左子树比右子树高,现左、右子树等高 */ 
							(*T)->bf=EH; *taller=FALSE;	break;
					case EH: /*  原本左、右子树等高,现因右子树增高而使树增高  */
							(*T)->bf=RH; *taller=TRUE; break;
					case RH: /*  原本右子树比左子树高,需要作右平衡处理 */ 
							RightBalance(T); *taller=FALSE; break;
				}
		}
	}
	return TRUE;
}
// 中递归遍历T
void InOrderTraverse(BiTree T)
{
	if (T == NULL) {
		return;
	}
	InOrderTraverse(T->lchild);	// 中序遍历左子树 
	printf("%d ", T->data);		// 显示结点数据 
	InOrderTraverse(T->rchild);	// 中序遍历后子树 
}
int main()
{    
	int i;
	int a[10]={3,2,1,4,5,6,7,10,9,8};
	BiTree T=NULL;
	int taller;
	for(i=0;i<10;i++)
	{
		InsertAVL(&T,a[i],&taller);
	}
	InOrderTraverse(T);
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值