一、静态查找表:
1.1顺序表的查找:
typedef struct
{
	ElemType *elem;
	int length;
}SSTable;
int Search_Seq(SSTable ST, KeyType key) 
{ 
	// 在顺序表ST中顺序查找其关键字等于key的数据元素。
	// 若找到,则函数值为该元素在表中的位置,否则为0。
	int i=0;
	ST.elem[0].key=key;   // "哨兵"
	for (i=ST.length;  ST.elem[i].key!=key;  --i);  // 从后往前找
	return i;      // 找不到时,i为0
}
1.2有序表的查找:
折半查找法(二分查找法)
int Search_Bin ( SSTable ST, KeyType key ) 
{  
	// 在有序表ST中折半查找其关键字等于key的数据元素。
	// 若找到,则函数值为该元素在表中的位置,否则为0。
	int low, high, mid;
	low = 1;  high = ST.length;    // 置区间初值
	while (low <= high) 
	{
		mid = (low + high) / 2;
		if (EQ(key , ST.elem[mid].key)) return mid;    // 找到待查元素
		else if (LT(key, ST.elem[mid].key)) high = mid - 1; // 继续在前半区间进行查找
		else low = mid + 1;    // 继续在后半区间进行查找
	}
	return 0;                 // 顺序表中不存在待查元素
}
1.3静态最优查找数:
1.4索引顺序表的查找:

其中包括两项内容:关键字项(其值为该子表内的最大关键字)和指针项(指示该子表的第一个记录在表中位置)。索引表按关键字有序,则表或者有序或者分块有序。
所谓"分块有序"指的是第i个子表中所有记录的关键字均大于第i-1个子表中的最大关键字,并且都小于第i+1个子表中的最小关键字。
因此,分块查找过程需分两步进行。先确定待查记录所在的块(子表),然后在块中顺序查找。由于由索引项组成的索引表按关键字有序,则确定块的查找可以用顺序查找,亦可用折半查找,而块中记录是任意排列的,则在块中只能是顺序查找。
二、动态查找表:
2.1二叉排序树:
定义:二叉排序树(Binary Sort Tree)或者是一棵空树;或者是具有下列性质的二叉树:(1)若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;(2)若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;(3)它的左、右子树也分别为二叉排序树。
查找过程:当二叉排序树不空时,首先将给定值和根结点的关键字比较,若相等,则查找成功,否则将依据给定值和根结点的关键字之间的大小关系,分别在左子树或右子树上继续进行查找。
查找:
取二叉链表作为二叉排序树的存储结构
BiTree SearchBST (BiTree T, KeyType key) {  // 算法9.5(a)
   // 在根指针T所指二叉排序树中递归地查找其关键字等于key的数据元素,
   // 若查找成功,则返回指向该数据元素结点的指针,否则返回空指针
   if (!T || EQ(key, T->data.key)) return T;  // 查找结束
   else if (LT(key, T->data.key)) 
      return SearchBST(T->lchild, key);  // 在左子树中继续查找 
   else 
      return SearchBST(T->rchild, key);  // 在右子树中继续查找
}
插入:
新插入的结点一定是一个新添加的叶子结点,并且是查找不成功时查找路径上访问的最后一个结点的左孩子或右孩子结点。修改搜索算法:
Status SearchBST(BiTree T, KeyType key, BiTree f, BiTree &p) 
{  
	// 在根指针T所指二叉排序树中递归地查找其关键字等于key的数据元素,
	// 若查找成功,则指针p指向该数据元素结点,并返回TRUE,
	// 否则指针p指向查找路径上访问的最后一个结点并返回FALSE,
	// 指针f指向T的双亲,其初始调用值为NULL
	if (!T) { p = f;  return FALSE; }                     // 查找不成功
	else if (EQ(key, T->data.key)) { p = T;  return TRUE; } // 查找成功
	else if (LT(key, T->data.key)) 
		return SearchBST(T->lchild, key, T, p);  // 在左子树中继续查找
	else  
		return SearchBST(T->rchild, key, T, p);  // 在右子树中继续查找
}
Status InsertBST(BiTree &T, ElemType e) 
{  
	// 当二叉排序树T中不存在关键字等于e.key的数据元素时,
	// 插入e并返回TRUE,否则返回FALSE
	BiTree p,s;
	if (!SearchBST(T, e.key, NULL, p)) // 查找不成功
	{   
		s = (BiTree)malloc(sizeof(BiTNode));
		s->data = e;  s->lchild = s->rchild = NULL;  
		if (!p) T = s;        // 插入 s 为新的根结点
		else if (LT(e.key, p->data.key)) p->lchild=s; // 插入s为左孩子
		else p->rchild = s;   // 插入 s 为右孩子
		return 
			TRUE;
	} else 
		return FALSE;  // 树中已有关键字相同的结点,不再插入
}
删除:
假设在二叉排序树上被删结点为*p(指向结点的指针为p),其双亲结点为*f(结点指针为f),且不失一般性,可设*p是*f的左孩子。
下面分三种情况进行讨论:
     (1)若*p结点为叶子结点,即PL和PR均为空树。由于删去叶子结点不破坏整棵树的结构,则只需修改其双亲结点的指针即可。
     (2)若*p结点只有左子树PL或者只有右子树PR,此时只要令PL或PR直接成为其双亲结点*f的左子树即可。显然,作此修改也不破坏二叉排序树的特性。
     (3)若*p结点的左子树和右子树均不空。显然,此时不能如上简单处理。从图可知,在删去*p结点之前,中序遍历该二叉树得到的序列为{…CLC…QLQSLSPPRF…},在删去*p之后,为保持其它元素之间的相对位置不变,可以有两种做法:其一是令*p的左子树为*f的左子树,而*p的右子树为*s的右子树,如图9.9(c)所示;其二是令*p的直接前驱(或直接后继)替代*p,然后再从二叉排序树中删去它的直接前驱(或直接后继)。如图9.9(d)所示,当以直接前驱*s替代*p时,由于*s只有左子树SL,则在删去*s之后,只要令SL为*s的双亲*q的右子树即可。
  
(a)*f为根的子树;(b)删除*p之前;(c)删除*p之后,PR作为*s右子树的情形;(d)删除*p之后,*s替代*p的情形
Status DeleteBST(BiTree &T,  KeyType key) 
{ 
	// 若二叉排序树T中存在关键字等于key的数据元素时,
	// 则删除该数据元素结点p,并返回TRUE;否则返回FALSE
	if (!T) 
		return FALSE;       // 不存在关键字等于key的数据元素
	else 
	{
		if (EQ(key, T->data.key))  // 找到关键字等于key的数据元素
			return Delete(T); 
		else if (LT(key, T->data.key)) 
			return DeleteBST(T->lchild, key);
		else 
			return DeleteBST(T->rchild, key);
	}
}
Status Delete(BiTree &p) 
{ 
	// 从二叉排序树中删除结点p,并重接它的左或右子树
	BiTree q, s;
	if (!p->rchild)  // 右子树空则只需重接它的左子树
	{  
		q = p;  p = p->lchild;  free(q);
	} 
	else if (!p->lchild)  // 只需重接它的右子树
	{  
		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) q->rchild = s->lchild;  // 重接*q的右子树
		else q->lchild = s->lchild;         // 重接*q的左子树
		free(s);    
	}
	return TRUE;
}
2.2平衡二叉树:
平衡二叉树(Balanced Binary Tree或Height-Balanced Tree)又称AVL树。它或者是一棵空树,或者是具有下列性质的二叉树:它的左子树和右子树都是平衡二叉树,且左子树和右子树的深度之差的绝对值不超过1。若将二叉树上结点的平衡因子BF(Balance Factor)定义为该结点的左子树的深度减去它的有子树的深度,则平衡二叉树上所有结点的平衡因子只可能是-1、0和1。只要二叉树上有一个结点的平衡因子的绝对值大于1,则该二叉树就是不平衡的。
一般情况下,假设由于在二叉排序树上插入结点而失去平衡的最小根结点的指针为a(即a是离插入结点最近,且平衡因子绝对值超过1的祖先结点),则失去平衡后进行调整的规律可归纳为下列四种情况:
(1)单向右旋平衡处理:由于在*a的左子树根结点的左子树上插入结点,*a的平衡因子由1增至2,致使以*a为根的子树失去平衡,则需进行一次向右的顺时针旋转操作。

(2)单向左旋平衡处理:由于在*a的右子树根结点的右子树上插入结点,*a的平衡因子由-1增至-2,致使以*a为根结点的子树失去平衡,则需进行一次向左的逆时针旋转操作。

(3)双向旋转(先左后右)平衡处理:由于在*a的左子树根结点的右子树上插入结点,*a的平衡因子由1增至2,致使以*a为根结点的子树失去平衡,则需进行两次旋转 (先左旋后右旋)操作。

      (4)双向旋转(先右后左)子衡处理:由于在*a的右子树根结点的左子树上插入结点,*a的平衡因子由-1增至-2,致使以*a为根结点的子树失去平衡,则需进行两次旋转(先右旋后左旋)操作。
typedef struct BSTNode
{
	ElemType data;
	int bf;
	struct BSTNode *lchild,*rchild;
}BSTNode,*BSTree;
void R_Rotate(BSTree &p) 
{ 
	// 对以*p为根的二叉排序树作右旋处理,处理之后p指向新的树根结点,
	// 即旋转处理之前的左子树的根结点
	BSTree lc;
	lc = p->lchild;            // lc指向*p的左子树根结点
	p->lchild = lc->rchild;    // lc的右子树挂接为*p的左子树
	lc->rchild = p;  p = lc;   // p指向新的根结点
}
void L_Rotate(BSTree &p) 
{  
	// 对以p↑为根的二叉排序树作左旋处理,处理之后p指向新的树根结点,
	// 即旋转处理之前的右子树的根结点
	BSTree rc;
	rc = p->rchild;            // rc指向*p的右子树根结点
	p->rchild = rc->lchild;    // rc的左子树挂接为*p的右子树
	rc->lchild = p;  p = rc;   // p指向新的根结点
}
#define LH +1   //左高
#define EH 0    //等高
#define RH -1   //右高
Status InsertAVL(BSTree &T, ElemType e, Boolean &taller) 
{ 
	// 若在平衡的二叉排序树T中不存在和e有相同关键字的结点,
	// 则插入一个数据元素为e的新结点,并返回1,否则返回0。
	// 若因插入而使二叉排序树失去平衡,则作平衡旋转处理,
	// 布尔变量taller反映T长高与否
	if (!T) {  // 插入新结点,树"长高",置taller为TRUE
		T = (BSTree) malloc (sizeof(BSTNode));  T->data = e;
		T->lchild = T->rchild = NULL;  T->bf = EH;  taller = TRUE;
	}
	else {
		if (EQ(e.key, T->data.key))    // 树中已存在和e有相同关键字的结点
		{ taller = FALSE;  return 0; } // 则不再插入
		if (LT(e.key, T->data.key)) {    // 应继续在*T的左子树中进行搜索
			if (InsertAVL(T->lchild, e, taller)==0) 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:   // 原本右子树比左子树高,现左、右子树等高
						T->bf = EH;  taller = FALSE;  break;   
			} 
		} 
		else {    // 应继续在T↑的右子树中进行搜索
			if (InsertAVL(T->rchild, e, taller)==0) 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:   // 原本右子树比左子树高,需要作右平衡处理
						RightBalance(T);  taller = FALSE;  break;
			} 
		} 
	} 
	return 1;
} 
void LeftBalance(BSTree &T) 
{  
	// 对以指针T所指结点为根的二叉树作左平衡旋转处理。
	// 本算法结束时,指针T指向新的根结点
	BSTree lc,rd;
	lc = T->lchild;    // lc指向*T的左子树根结点
	switch (lc->bf) 
	{  // 检查*T的左子树的平衡度,并作相应平衡处理
    case LH:   // 新结点插入在*T的左孩子的左子树上,要作单右旋处理
        T->bf = lc->bf = EH; 
        R_Rotate(T);   
        break;  
    case RH:      // 新结点插入在*T的左孩子的右子树上,要作双旋处理
        rd = lc->rchild;   // 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->lchild);  // 对*T的左子树作左旋平衡处理
        R_Rotate(T);          // 对*T作右旋平衡处理
	} 
}
2.3 B-树:
B-树是一种平衡的多路查找树,它在文件系统中很有用。
一棵m阶的B-树,或为空树,或为满足下列特性的m叉树:
(1)树中每个结点至多有m棵子树;
(2)若根结点不是叶子结点,则至少有两棵子树;
(3)除根之外的所有非终端结点至少有ceil(m/2)棵子树;
(4)所有的非终端结点中包含下列信息数据(n, A0, K1, A1, K2, A2, …, Kn, An);
(5)所有的叶子结点都出现在同一层次上,并且不带信息(可以看作是外部结点或查找失败的结点,实际上这些结点不存在,指向这些结点的指针为空)。
#define m 3			//B-树的阶
typedef struct BTNode
{
	int keynum;     //结点中关键字的个数,即结点的大小
	struct BTNode *parent;//指向双亲结点
	KeyType key[m+1];//关键字向量,0号未用
	struct BTNode *ptr[m+1];//子树指针向量
	Record *recptr[m+1];//记录指针向量,0号未用
}BTNode,*BTree;//B-树结点和B-树类型
typedef struct
{
	BTNode *pt;      //指向找到的结点
	int i;           //1..m,在结点中的关键字的序号
	int tag;         //1查找成功,0查找失败
}Result;
Result SearchBTree(BTree T, KeyType K)
{ 
	// 在m阶B树T上查找关键字K,返回结果(pt,i,tag).若查找成功,则特征值tag=1,指针pt
	//所指结点中第i个关键字等于K;否则特征值tag=0,
	//等于K的关键字应该插入在指针pt所指结点中第i和第i+1个关键字之间
	p = T;  q = NULL;  found = FALSE;  i = 0; // 初始化,p指向待查结点,q指向p的双亲
	while (p && !found) 
	{
		i = Search(p, K);  // 在p->key[1..keynum]中查找i,使得:p->key[i]<=K<p->key[i+1]
		if (i>0 && p->key[i]==K) found = TRUE;    // 找到待查关键字
		else { q = p;  p = p->ptr[i]; }
	}
	if (found)   // 查找成功
		return (p,i.1); 
	else       // 查找不成功
		return (q,i,0);   // 返回结果信息: K的位置(或插入位置)
} 
  插入:

void Insert(BTree &q, int i, KeyType x, BTree ap) {
	// insert the key X between the key[i] and key[i+1] 
	// at the pointer node q
	int n = q->keynum;
	for (int j=n; j>i; j--) {
		q->key[j+1] = q->key[j];
		q->ptr[j+1] = q->ptr[j];
	}
	q->key[i+1] = x;
	q->ptr[i+1] = ap;
	if (ap) ap->parent = q;  
	q->keynum++;
}
void split(BTree &q, int s, BTree &ap) {
	//move key[s+1...m],p->ptr[s...m] int the new pointer *ap
	int i,j,n=q->keynum;
	ap = (BTree)malloc(sizeof(BTNode));
	ap->ptr[0] = q->ptr[s];
	for (i=s+1,j=1; i<=n; i++,j++) {
		ap->key[j] = q->key[i];
		ap->ptr[j] = q->ptr[i];
	}
	ap->keynum = n-s;
	ap->parent = q->parent;
	for (i=0; i<=n-s; i++) 
		//refresh the parent_pointer of the subpointer in new pointer *ap
		if (ap->ptr[i]) ap->ptr[i]->parent = ap;
		q->keynum = s-1;
}
void NewRoot(BTree &T, BTree p, KeyType x, BTree ap) {
	T = (BTree)malloc(sizeof(BTNode));
	T->keynum = 1;  T->ptr[0] = p;  T->ptr[1] = ap;  T->key[1] = x;
	//if (f) ShowBTNode(T);
	if (p) p->parent= T;  
	// refresh the parent_pointer of sub_pointers in *p and *q
	if (ap) ap->parent = T;
	T->parent = NULL;
}
Status InsertBTree(BTree &T, KeyType K, BTree q, int i) { // 算法9.14
	// 在m阶B树T上结点*q的key[i]与key[i+1]之间插入关键字K。
	// 若引起结点过大,则沿双亲链进行必要的结点分裂调整,使T仍是m阶B树。
	BTree ap;
	int finished, needNewRoot, s;
	KeyType x;
	if (!q)                      // T是空树(参数q初值为NULL)
		NewRoot(T, NULL, K, NULL); // 生成仅含关键字K的根结点*T
	else {
		x = K;  ap = NULL;  finished = needNewRoot = FALSE;     
		while (!needNewRoot && !finished) {
			Insert(q, i, x, ap); // 将x和ap分别插入到q->key[i+1]和q->ptr[i+1]
			if (q->keynum < m) finished = TRUE;  // 插入完成
			else {  // 分裂结点*q
				// 将q->key[s+1..m], q->ptr[s..m]和
				// q->recptr[s+1..m]移入新结点*ap
				s = (m+1)/2;   split(q, s, ap);   x = q->key[s];
				if (q->parent) {  // 在双亲结点*q中查找x的插入位置
					q = q->parent;  i = Search(q, x);  
				} else needNewRoot = TRUE;
			} 
		}
		if (needNewRoot)        // 根结点已分裂为结点*q和*ap
			NewRoot(T, q, x, ap); // 生成新根结点*T,q和ap为子树指针
	}
	return OK;
} 
  删除:

   (1)被删关键字所在结点中的关键字数目不小于ceil(m/2),则只需从该结点中删去该关键字Ki和相应指针Ai,树的其它部分不变。删除12:

  (2)被删关键字所在结点中的关键字数目等于ceil(m/2)-1,而与该结点相邻的右兄弟(或左兄弟)结点中的关键字数目大于ceil(m/2)-1,则需将其兄弟结点中的最小(或最大)的关键字上移至双亲结点中,而将双亲结点中小于(或大于)且紧靠该上移关键字的关键字下移至被删关键字所在结点中。删除50:

  (3)被删关键字所在结点和其相邻的兄弟结点中的关键字数目均等于ceil(m/2)-1。假设该结点有右兄弟,且其右兄弟结点地址由双亲结点中的指针Ai所指,则在删去关键字之后,它所在结点中剩余的关键字和指针,加上双亲结点中的关键字Ki一起,合并到 Ai所指兄弟结点中(若没有右兄弟,则合并至左兄弟结点中)。删除53:
删除37:

2.4 B+树:
B+树是应文件系统所需而出的一种B-树的变型树。一棵m阶的B+树和m阶的B-树的差异在于:
(1)有n棵子树的结点中含有n个关键字;
(2)所有的叶子结点中包含了全部关键字的信息,及指向含这些关键字记录的指针,且叶子结点本身依关键字的大小自小而大顺序链接。
    (3)所有的非终端结点可以看成是索引部分,结点中仅含有其子树(根结点)中的最大(或最小)关键字。
三、哈希表
  哈希表:根据设定的哈希函数H(key)和处理冲突的方法将一组关键字映象到一个有限的连续的地址集(区间)上,并以关键字在地址集中的“象”作为记录在表中的存储位置,这种表便称为哈希表,这一映象过程称为哈希造表或散列,所得存储位置称哈希地址或散列地址。
常用的构造哈希函数的方法有:
1.直接定址法
  取关键字或关键字的某个线性函数值为哈希地址。
H(key)=key 或 H(key)=a·key+b
其中a和b为常数(这种哈希函数叫做自身函数)。由于直接定址所得地址集合和关键字集合的大小相同。因此,对于不同的关键字不会发生冲突。
2.数字分析法 
    假设关键字是以r为基的数(如:以10为基的十进制数),若哈希表中可能出现的关键宇都是事先知道的,则可取关键字的若干数位组成哈希地址。
3.平方取中法
    取关键字平方后的中间几位为哈希地址。
4.折叠法
    将关键字分割成位数相同的几部分(最后一部分的位数可以不同),然后取这几部分的叠加和(舍去进位)作为哈希地址,这方法称为折叠法(folding)。
5.除留余数法
    取关键字被某个不大于哈希表表长m的数p除后所得余数为哈希地址。
      H(key)=key MOD p p≤m
由经验得知:一般情况下可以选p为质数或不包含小于20的质因素的合数。
6.随机数法 
    选择一个随机函数,取关键字的随机函数值为它的哈希地址。
H(key)=random (key),其中random为随机函数。
  通常,当关键字长度不等时采用此法构造哈希函数较恰当。
处理冲突的方法:
1.开放定址法
      Hi=(H(key)+di)MOD m         i=1,2,…,k (k≤m-1) (9-25)
    其中:H(key)为哈希函数;m为哈希表表长;di为增量序列,可有下列三种取法:
    (1)di=1,2,3,…,m-1,称线性探测再散列;“二次聚集”(发生的两个第一个哈希地址不同的记录争夺同一个后继哈希地址的现象),但可以保证做到,只要哈希表未填满,总能找到一个不发生冲突的地址
    (2)di=1,-1,4,-4,9,-9......(k≤m/2)称二次探测再散列;哈希表长m为形如 4j+3(j为整数)的素数。
    (3)di=伪随机数序列,称伪随机探测再散列。
2.再哈希法
      Hi=RHi(key) 
    RHi均是不同的哈希函数,即在同义词产生地址冲突时计算另一个哈希函数地址,直到冲突不再发生。这种方法不易产生“聚集”,但增加了计算的时间。
3.链地址法
    将所有关键字为同义词的记录存储在同一线性链表中。
  
4.建立一个公共溢出区
哈希表的装填因子:
        
查找
//---开放定址哈希表的存储结构---
int hashsize[]={997,...}   //哈希表容量递增表,一个合适的素数序列
typedef struct
{
	ElemType *elem;        //数据元素存储基址,动态分配数组
	int count;             //当前数据元素个数
	int sizeindex;         //hashsize[sizeindex]为当前容量
}HashTable;
#define SUCCESS 1
#define UNSUCCESS 0
#define DUPLICATE -1
Status SearchHash(HashTable H, HKeyType K, int &p, int &c) 
{  
	// 在开放定址哈希表H中查找关键码为K的元素,
	// 若查找成功,以p指示待查数据元素在表中位置,并返回SUCCESS;
	// 否则,以p指示插入位置,并返回UNSUCCESS,
	// c用以计冲突次数,其初值置零,供建表插入时参考
	p = Hash(K);                          // 求得哈希地址
	while ((H.elem[p].key != NULLKEY) &&  // 该位置中填有记录
		!equal(K, (H.elem[p].key)))   // 并且关键字不相等
		collision(p, ++c);                 // 求得下一探查地址p
	if (equal(K, (H.elem[p].key)))
		return SUCCESS;        // 查找成功,p返回待查数据元素位置
	else return UNSUCCESS;    // 查找不成功(H.elem[p].key == NULLKEY),
	// p返回的是插入位置
}
  插入  
Status InsertHash(HashTable &H, HElemType e) 
{ 
	// 查找不成功时插入数据元素e到开放定址哈希表H中,并返回OK;
	// 若冲突次数过大,则重建哈希表
	int c = 0;
	int p = 0;
	if (SearchHash(H, e.key, p, c) == SUCCESS )
		return DUPLICATE;        // 表中已有与e有相同关键字的元素
	else if (c < H.cursize)     // 冲突次数c未达到上限,(阀值c可调)
	{   
		H.elem[p] = e;  ++H.count;  return SUCCESS;  // 插入e
	} else 
	{
		RecreateHashTable(H);  // 重建哈希表
		return UNSUCCESS;
	} 
}
......
 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号