查找
线性表的查找
<1>顺序查找
<2>二分查找
递归算法 typedef struct { KeyType key; InfoType otherinfo; //此类型依赖于应用 }NodeType; typedef NodeType SeqList[n]; int BinSearch(SeqList R, int low, int high, KeyType K) { //在有序表R[low,high]中进行二分查找,成功时返回结点的位置,失败时返回零 int min; if(low<=high){ //当前查找区间R[low..high]非空 { mid=(low+high)/2;//置当前查找区间上、下界的中值 if(R[mid].key==K) return mid; //查找成功返回 else if(R[mid].kdy>K) return BinSearch(R,low,mid-1,K); //继续在R[low..mid-1]中查找 else return BinSearch(R,low,mid-1,K); //继续在R[mid+1..high]中查找 } return -1; //当low>high时表示查找区间为空,查找失败 } //BinSeareh 非递归查找法 int BinSearch(SeqList R,KeyType K) { //在有序表R[1..n]中进行二分查找,成功时返回结点的位置,失败时返回零 int low=1,high=n,mid; //置当前查找区间上、下界的初值 while(low<=high) { //当前查找区间R[low..high]非空 mid=(low+high)/2; if(R[mid].key==K) return mid; //查找成功返回 if(R[mid].kdy>K) high=mid-1; //继续在R[low..mid-1]中查找 else low=mid+1; //继续在R[mid+1..high]中查找 } return 0; //当low>high时表示查找区间为空,查找失败 } //BinSeareh
二叉排序树
<1>二叉排序树的定义(其中的关键字不重复)
要么是空树,要么满足如下条件(BST性质):每个节点的左子树上所有节点的值均小于该节点的值,右子树上所有节点的值均大于等于该节点的值;
typedef int KeyType; //假定关键字类型为整数 typedef struct BiTNode { KeyType key; //关键字项 InfoType otherinfo; //其它数据域,InfoType视应用情况而定,下面不处理它 struct BiTNode *lchild, *rchild; }BiTNode, *BiTree;
<2>二叉排序树的查找
/* 递归查找二叉排序树T中是否存在key, */ /* 指针f指向T的双亲,其初始调用值为NULL */ /* 若查找成功,则指针p指向该数据元素结点,并返回TRUE;*/
/* 若查找不成功,指针p指向查找路径上访问的最后一个结点并返回FALSE,这样方便后续插入节点,若p为null则表示该树为空。*/ Status SearchBST(BiTree T, KeyType key, BiTree f, BiTree *p) { if (T == NULL) /* 若输入的节点为空,则查找不成功 */ { *p = f; return FALSE; } else if (key == T->key) /* 查找成功 */ { *p = T; return TRUE; } else if (key < T->key) return SearchBST(T->lchild, key, T, p); /* 在左子树中继续查找 */ else return SearchBST(T->rchild, key, T, p); /* 在右子树中继续查找 */ }
<3>二叉排序树的插入插入算法:查找关键字key,若查找成功,则不用插入。若查找失败,p为null,或则为要插入的节点的双亲节点。
/* 当二叉排序树T中不存在关键字等于key的数据元素时,插入key并返回TRUE,否则返回FALSE */ Status InsertBST(BiTree *T, KeyType key) { BiTree p,s; if (SearchBST(*T, key, NULL, &p)) /* 查找成功,则树中已有关键字相同的结点,不再插入 */ return FALSE; /* 查找不成功 */ s = (BiTree)malloc(sizeof(BiTNode)); s->data = key; s->lchild = s->rchild = NULL; if (!p) *T = s; /* 插入s为新的根结点 */ else if (key < p->key) p->lchild = s; /* 插入s为左孩子 */ else p->rchild = s; /* 插入s为右孩子 */ return TRUE; }
<4>删除节点(不改变二叉排序树的BST性质),分三种情况:
a,*p是叶子节点,无须连接*p的子树,只需将*p的双亲*parent中指向*p的指针域置空即可。
b,*p只有一个孩子*child只需将*child和*p的双亲直接连接后,即可删去*p。有四种情况,*p是否为根节点,*child为左或右孩子。具体【参见动画演示】
c,*p有两个孩子,先令q=p,将被删结点的地址保存在q中;然后找*q的中序后继*p,并在查找过程中仍用parent记住*p的双亲位置。*q的中序后继*p一定是*q的右子树中最左下的结点,它无左子树。因此,可以将删去*q的操作转换为删去的*p的操作,即在释放结点*p之前将其数据复制到*q中,就相当于删去了*q。具体【参见动画演示】。
/*在二叉排序树*Tptr中删去关键字为key的结点*/ Status DeleteBST(BiTree *T, KeyType key) { BiTree parent=NULL, p=*T; //用p指向要删除的节点,parent指向*p的双亲 BiTree q, child; while(p) //从根开始查找关键字为key的待删结点 { if(p->key == key) break; parent = p; p = (key < p->key)? p->lchild:p->rchild; //在p的左或右子树中继续找 } if(p == NULL) //找不到被删结点则返回FALSE return FALSE; /* 将情况(3)转换为情况(2),而情况(1)相当于是情况(2)中child=NULL的状况, q保存被删节点的地址,找到*q的中序后继*p(或中序前继), *p属于(1)(2)情况,然后将后继节点的数据复制到*q节点,接上后继节点的子树后删除该节点*/ q = p; if(q->lchild && q->rchild) for(parent=p, p=p->rchild; p->lchild; parent=p, p=p->lchild); child = (p->rchild)? p->rchild:p->lchild; //若是情况(2),则child非空;否则child为空 if(parent == NULL) //说明*p属于(1)(2),且*p为根节点,删除*p后应修改根指针 *T = child; else //属于(1)(2)且p不是根节点或属于情况(3),删除后不用修改根指针 { /* 删除*p,*p的孩子和*p的双亲进行连接 */ if(p == parent->lchild) parent->lchild=child; else parent->rchild = child; /* 情况(3)需将*p的数据复制到*q,若还有其它数据域亦需复制 */ if(p != q) q->key = p->key; } //endif free(p); return TURE; }