深入理解数据结构——查找算法

#include <iostream>
#include <string>

using namespace std;
typedef int EtypeKey;
typedef int DataType;

struct EType {
	EtypeKey key;
	DataType data;
};

struct LinearList {
	//查找表类型
	EType* elem;//指向顺序表的指针
	int len;
	int maxsize;
};

//顺序查找算法
int Search(LinearList &L, EtypeKey SearchKey) {
	//在L中顺序查找关键字为SearchKey的
	//查找成功时返回该记录的下标序号,失败是返回-1
	int i;
	i = 0;
	while (i < L.len && L.elem[i].key != SearchKey)
		i++;
	if (L.elem[i].key == SearchKey)
		return i;
	else
		return -1;
}

//顺序查找改进算法
int Search(LinearList& L, EtypeKey SearchKey) {
	//在L中顺序查找关键字为SearchKey的
	//查找成功时返回该记录在表中的位置,失败是返回0
	L.elem[0].key = SearchKey;//设置“哨兵”
	
	int i;
	for (int i = L.len; L.elem[i].key != SearchKey; --i);
	return i;
}

int BinarySearch(LinearList& L, EtypeKey SearchKey,int n) {
	//如果找到则返回该记录的下标,否则返回-1

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


//分块查找的算法
struct IndexType {
	EtypeKey key;
	int link;
};

int IndexSearch(IndexType ls[],EType L[],
	int m,int blocksize,EtypeKey SearchKey) {

	//顺序表为L,块长为blocksize

	int i, j; i = 0;
	while (i<m && SearchKey>ls[i].key)
		i++;
	if (i >= m)
		return -1;
	else {
		//在顺序表中顺序查找
		j = ls[i].link;
		while (SearchKey != L[j].key && j - ls[i].link < blocksize)
			j++;
		if (SearchKey != L[j].key)
			return j;
		else
			return -1;
	}
}

/**************************ALV树算法****************************/

#define EQ(a,b)   ((a)==(b))
#define LT(a,b)   ((a)<(b))
#define LQ(a,b)   ((a)>(b))

#define LH +1    //左高
#define EH 0	//等高
#define RH -1	//右高
#define NULL 0

struct BLNode {
	int data;
	int bf; //节点平衡因子
	BLNode* LChird, * RChird;//左右孩指针
} ;
typedef BLNode* BLree;

//对*p为根的二叉排序树作右旋处理
void R_Rotate(BLree& p) {

	BLree lc = p->LChird;//lc指向*p的左子树节点

	p->LChird = lc->RChird;//lc的右子树挂接为*p的左子树
	lc->RChird = p;
	p = lc;//p指向新的节点
}

//对*p为根的二叉排序树作左旋处理
void L_Rotate(BLree& p) {

	BLree rc = p->RChird;//lc指向*p的左子树节点

	p->RChird = rc->LChird;//lc的左子树挂接为*p的右子树
	rc->LChird = p;
	p = rc;//p指向新的节点
}



//对以指针T所指节点为根的二叉树作左平衡旋转处理
void LeftBalance(BLree& T) {

	BLree lc, rd;
	lc = T->LChird;//lc指向*T的左子树根节点

	switch (lc->bf) {//检查*T的左子树的平衡度,并作相应平衡处理
	case LH:		//新节点插入在*T的左孩子的左子树上,要作单右旋处理
		T->bf = lc->bf = EH;
		R_Rotate(T); break;
	case RH:       //新节点插入在*T的左孩子的左子树上,要作双旋处理
		rd = lc->RChird;   //rd指向*T的左孩子的左子树根
		switch (rd->bf) {  //修改*T及其左孩子的平衡因子
		case LH:T->bf = RH; lc->bf = EH; break;
		case EH:T->bf =lc->bf = EH; break;
		case RH:T->bf = EH; lc->bf = LH; break;
		}
		rd->bf = EH;
		L_Rotate(T->LChird);//对*T的左子树作左旋平衡处理
		R_Rotate(T);//对*T的右旋平衡处理
	}
}



//对以指针T所指节点为根的二叉树作右平衡旋转处理
void RightBalance(BLree& T) {

	BLree rc, ld;
	rc = T->RChird;//lc指向*T的you子树根节点

	switch (rc->bf) {//检查*T的左子树的平衡度,并作相应平衡处理
	case RH:		//新节点插入在*T的you孩子的you子树上,要作单zuo旋处理
		T->bf = rc->bf = EH;
		L_Rotate(T); 
		break;
	case LH:       //新节点插入在*T的you孩子的左子树上,要作双旋处理
		ld = rc->LChird;   //ld指向*T的you孩子的左子树根
		switch (ld->bf) {  //修改*T及其左孩子的平衡因子
		case LH:T->bf = EH; rc->bf = RH; break;
		case EH:T->bf = rc->bf = EH; break;
		case RH:T->bf = LH; rc->bf = EH; break;
		}
		ld->bf = EH;
		R_Rotate(T->RChird);//对*T的左子树作YOU旋平衡处理
		L_Rotate(T);//对*T的ZUO旋平衡处理
	}
}



//删除节点时左平衡旋转处理
void LeftBalance_div(BLree& p, int& shorter) {
	BLree p1, p2;
	if (p->bf == 1) {//p节点的左子树高,删除节点后p的bf-1.树变矮
		p->bf = 0;
		shorter = 1;
	}
	else if (p->bf == 0) {//p节点的左you子树deng高,删除节点后p的bf-1.树gao不变
		p->bf = -1;
		shorter = 0;
	}
	else {//p节点的you子树高
		p1 = p->RChird;

		if (p1->bf == 0) {
			//p1节点的左you子树等高,删除节点后p的bf=0,进行zuo旋处理,树变矮
			L_Rotate(p);
			p1->bf = 1;
			p->bf = -1;
			shorter = 0;
		}
		else if (p1->bf == -1) {
			L_Rotate(p);
			p1->bf = 0;
			p->bf = 0;
			shorter = 1;
		}
		else {//p1的左子树高,进行双旋处理(先右旋后左旋),树变矮
			p2 = p1->LChird;
			p1->LChird = p2->RChird;
			p2->RChird = p1;

			p->RChird = p2->LChird;
			p2->LChird = p;

			if (p2->bf == 0) {
				p->bf = 0;
				p1->bf = 0;
			}
			else if (p2->bf == -1) {
				p->bf = 1;
				p1->bf = 0;

			}
			else {
				p->bf = 0;
				p1->bf = -1;
			}
			p2->bf = 0;
			p = p2;
			shorter = 1;
		}
	}
}


//删除节点时you平衡旋转处理
void RightBalance_div(BLree& p, int& shorter) {
	BLree p1, p2;
	if (p->bf == -1) {
		p->bf = 0;
		shorter = 1;
	}
	else if (p->bf == 0) {
		p->bf = 1;
		shorter = 0;
	}
	else {
		p1 = p->LChird;

		if (p1->bf == 0) {

			R_Rotate(p);
			p1->bf = -1;
			p->bf = 1;
			shorter = 0;
		}
		else if (p1->bf == 1) {
			R_Rotate(p);
			p1->bf = 0;
			p->bf = 0;
			shorter = 1;
		}
		else {//p1的左子树高,进行双旋处理(先右旋后左旋),树变矮
			p2 = p1->RChird;
			p1->RChird = p2->LChird;
			p2->LChird = p1;

			p->LChird = p2->RChird;
			p2->RChird = p;

			if (p2->bf == 0) {
				p->bf = 0;
				p1->bf = 0;
			}
			else if (p2->bf == 1) {
				p->bf = 1;
				p1->bf = 0;

			}
			else {
				p->bf = 0;
				p1->bf = 1;
			}
			p2->bf = 0;
			p = p2;
			shorter = 1;
		}
	}
}


//ALV树插入算法
bool InsertAVL(BLree& T, int e,bool &taller) {
	/*
	若平衡二叉排序树T中不存在和e有相同关键码的节点,则插入一个数据元素为e的
	新节点,并返回1,否则返回0.
	若因为插入而使得二叉排序树失去平衡,则作平衡旋转处理

	布尔型变量taller反映T长高与否

	*/

	if (!T) {//插入新节点,树长高,置taller为true
		T = (BLree)malloc(sizeof(BLree));
		T->data = e;
		T->LChird = T->RChird = NULL;
		T->bf = EH;
		taller = true;
	}
	else {
		if (EQ(e, T->data)) {//树中已存在相同关键字的节点
			taller = false;
			printf("已存在相同关键字的节点");
			return 0;
		}//不再插入
		if (LT(e, T->data)) {
			if (!InsertAVL(T->LChird, e, taller))
				return 0;//未插入
			if(taller)//已插入到*T的左子树,且左子树长高
				switch (T->bf) {//检查*T的平衡度
					case LH://原本左子树比右子树高,需要做左平衡处理
						LeftBalance(T);
						taller = false;
						break;
					case EH://原本左子树和右子树等高,先因为左子树增高而使得树增高
						T->bf = LH;
						taller = true;
						break;
					case RH://原本you子树比zuo子树高,需要左右子树等高
						T->bf = EH;
						taller = false;
						break;
				}
		}
		else {//应该继续再*T的右子树进行搜索
			if (!InsertAVL(T->RChird, e, taller))
				return 0;//未插入
			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://原本you子树比zuo子树高,需要做you平衡处理
						RightBalance(T);
						taller = false;
						break;
				}
		}
	}
	return 1;
}

//ALV树删除算法

void Delete(BLree q, BLree &r,int &shorter) {
	//删除节点
	if (r->RChird == NULL) {
		q->data = r->data;
		q = r;
		free(q);
		shorter = 1;
	}
	else {
		Delete(q, r->RChird, shorter);
		if (shorter == 1)
			RightBalance_div(r, shorter);
	}

}

int DeleteAVL(BLree& p, int x, int& shorter) {
	//平衡二叉树的删除操作
	int k;
	BLree q;
	if (p == NULL) {
		printf("不存在要删除的关键字!!\n");
		return 0;
	}
	else if(x<p->data){//p的左子树中进行删除
		k = DeleteAVL(p->LChird, x, shorter);
		if (shorter == 1)
			LeftBalance_div(p, shorter);
		return k;
	}
	else if (x > p->data) {
		k = DeleteAVL(p->RChird, x, shorter);
		if (shorter == 1)
			RightBalance_div(p, shorter);
		return k;
	}
	else {
		q = p;
		if (p->RChird == NULL) {//右子树为空,只需要重接它的左子树
			p = p->LChird;
			free(q);
			shorter = 1;
		}
		else if (p->LChird == NULL) {//zuo子树为空,只需要重接它的you子树
			p = p->RChird;
			free(q);
			shorter = 1;
		}
		else {//左右子树均不为空
			Delete(q, q->LChird, shorter);
			if (shorter == 1)
				LeftBalance_div(p, shorter);
			p = q;
		}
		return 1;
	}
}


/**********************B-算法***********************/

#define m 5   //定义树的度
#define KeyType int   //定义关键码

struct BTNode {
	//定义节点类型
	int KeyNum;//关键码个数
	BTNode* parent;//指向父节点的指针
	KeyType Key[m + 1];//关键码数组
	BTNode* NodePtr[m + 1];//孩子节点指针数组
	EType* Elem[m + 1];//数据元素,如文件中的记录号
};

struct Result {
	//定义结果类型
	BTNode* NodePtr;//节点指针
	int NodePos;//节点位置(在一个节点内)
	int RetFlag;//返回标志
};

struct Btree {
	//B-树结构定义

	BTNode* RootPtr;//根节点指针
	int ElemNum;//元素个数
	int NodeNum;//节点个数
	int ChildNum; //孩子个数
};

//在一个节点内顺序查找
int SqSearch(BTNode* BT, KeyType SearchKey) {
	int i = 0, j;
	for (j = 1; j <= BT->Key[j]; j++)
		if (SearchKey >= BT->Key[j])
			i = j;
	return i;
}
//B-树上的查找算法

void B_Search(Btree* bt, KeyType SearchKey, Result& x) {
	BTNode* current, * parent;
	int i = 0; 
	bool Found = false;
	current = bt->RootPtr;//从根节点开始
	parent = NULL;
	while (current && !Found) {
		//循环至查找到的叶子节点或已查到所需关键字
		i = SqSearch(current, SearchKey);//在一个节点内顺序查找
		if (i > 0 && current->Key[i] == SearchKey)
			Found = true;//相等则查找成功
		else {
			parent = current;
			current = current->NodePtr[i];
		}
	}
	if (Found) {
		//查找成功
		x.NodePos = i;
		x.NodePtr = current;
		x.RetFlag = true;
	}
	else {
		x.NodePos = i;
		x.NodePtr = parent;
		x.RetFlag = false;
	}
	
}


/****************************哈希表法********************************/
EType* ht;

bool* Empty;
int n;
void HashTable(int divisor) {
	//构造函数,分配哈希函数
	n = divisor;
	ht = new EType[n];
	Empty = new bool[n];
	for (int i = 0; i < n; i++)
		Empty[i] = true;
}

//基于开放定址法哈希表查找算法
int HashSearch(KeyType& SearchKey) {
	//查询一个开地址表,如果存在,则返回k的位置,否则返回插入点(若空间足够)

	int i = SearchKey % n;//起始桶
	int j = i;
	do {
		if (Empty[j] || ht[j].key == SearchKey)
			return j;
		j = (j + 1) / n;//下一个桶
	} while (j != i);
	return j;
}

bool Search(KeyType& SearchKey, EType& result) {
	//搜索与k匹配的元素
	int b = HashSearch(SearchKey);
	if (Empty[b] || ht[b].key != SearchKey)
		return false;
	result = ht[b];
	return true;
}

//基于开放定址法哈希表的插入
bool HashInsert(EType& x, KeyType& SearchKey) {
	KeyType SearchKey = x.key;
	int b = HashSearch(SearchKey);
	if (Empty[b]) {
		Empty[b] = false;
		ht[b] = x;
		return true;
	}
	return false;
}

//链地址法
struct ChainNode {
	KeyType Key;
	ChainNode* link;
};
//基于链地址法哈希表查找算法
ChainNode* HashSearch(ChainNode *a[],KeyType SearchKey,int mod) {
	//在链接址的哈希表a中查找关键字SearchKey,a[]中存放指向链节点的指针

	ChainNode* p;
	int i;
	i = SearchKey % mod;
	p = a[i];
	while (p != NULL && p->Key != SearchKey)
		p = p->link;
	if (p == NULL)
		return NULL;//查找不到时返回空值
	else
		return p;//查找到时返回该记录的地址
}
//基于链地址法哈希表插入算法
bool HashInsert(ChainNode* a[], KeyType SearchKey, int mod) {
//在链地址的哈希表a中若查找不到关键字为SearchKey记录则插入该记录
	ChainNode*pre,* p,*q;
	int i;
	i = SearchKey % mod;
	p = a[i];
	while (p != NULL && p->Key != SearchKey) {
		//在对应的链表中查找关键字为SearchKey的记录
		pre = p;
		p = p->link;
	}
	if (p == NULL) {
		//未查找到时插入该记录在对应的链表尾
		q = new ChainNode;
		q->Key = SearchKey;
		q->link = NULL;
		if (a[i] == NULL)
			a[i] = q;                          //在该链插入第一个记录
		else
			pre->link = q;                     //在该链插入后续记录
		return true;							//插入新节点返回
	}
	return false;			//未插入返回

}
		

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
逻辑结构:描述数据元素之间的逻辑关系,如线性结构(如数组、链表)、树形结构(如二叉树、堆、B树)、图结构(有向图、无向图等)以及集合和队列等抽象数据类型。 存储结构(物理结构):描述数据在计算机中如何具体存储。例如,数组的连续存储,链表的动态分配节点,树和图的邻接矩阵或邻接表表示等。 基本操作:针对每种数据结构,定义了一系列基本的操作,包括但不限于插入、删除、查找、更新、遍历等,并分析这些操作的时间复杂度和空间复杂度。 算法算法设计:研究如何将解决问题的步骤形式化为一系列指令,使得计算机可以执行以求解问题。 算法特性:包括输入、输出、有穷性、确定性和可行性。即一个有效的算法必须能在有限步骤内结束,并且对于给定的输入产生唯一的确定输出。 算法分类:排序算法(如冒泡排序、快速排序、归并排序),查找算法(如顺序查找、二分查找、哈希查找),图论算法(如Dijkstra最短路径算法、Floyd-Warshall算法、Prim最小生成树算法),动态规划,贪心算法,回溯法,分支限界法等。 算法分析:通过数学方法分析算法的时间复杂度(运行时间随数据规模增长的速度)和空间复杂度(所需内存大小)来评估其效率。 学习算法数据结构不仅有助于理解程序的内部工作原理,更能帮助开发人员编写出高效、稳定和易于维护的软件系统。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

南叔先生

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

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

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

打赏作者

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

抵扣说明:

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

余额充值