本章需要掌握:
1、顺序查找
2、折半查找
3、二叉排序树原理及建树
4、二叉排序树删除
5、真题
1、顺序查找 一个简单的加了哨兵的查找顺序表,上面是核心,下面是实践
1 2 3 4 5 6 int Search_Seq (SSTable ST,ElemType key) { ST.elem[0 ]=key; for (int i=ST.TableLen-1 ;ST.elem[i]!=key;i--); return i; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 #include <stdio.h> #include <stdlib.h> #include <time.h> typedef int ElemType;typedef struct { ElemType* elem; int TableLen; }SSTable; void ST_Init (SSTable &ST,int len) { ST.TableLen=len+1 ; ST.elem= (ElemType*)malloc (sizeof (ElemType)*ST.TableLen); int i; srand (time (NULL )); for (i = 1 ; i < ST.TableLen; i++) { ST.elem[i] = rand () % 100 ; } } void ST_print (SSTable ST) { int i; for (i=1 ;i<ST.TableLen;i++) { printf ("%3d" ,ST.elem[i]); } printf ("\n" ); } int Search_Seq (SSTable ST,ElemType key) { ST.elem[0 ]=key; int i; for (i=ST.TableLen-1 ;ST.elem[i]!=key;i--); return i; } int main () { SSTable ST; ST_Init (ST, 10 ); ST_print (ST); ElemType key; printf ("please input search key:\n" ); scanf ("%d" ,&key); int pos; pos = Search_Seq (ST, key); if (pos) { printf ("find key,pos=%d\n" ,pos); }else { printf ("not find\n" ); } return 0 ; }
2、折半查找 一个简单的排序顺序表的,上面是核心,下面是实践
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 int BinarySearch (SSTable L, ElemType key) { int low=0 ; int high=L.TableLen-1 ; int mid; while (low<=high) { mid=(low+high)/2 ; if (key>L.elem[mid]) { low=mid+1 ; } else if (key<L.elem[mid]) { high=mid-1 ; }else { return mid; } } return -1 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 #include <stdio.h> #include <stdlib.h> #include <time.h> typedef int ElemType;typedef struct { ElemType* elem; int TableLen; }SSTable; void ST_Init (SSTable& ST, int len) { ST.TableLen = len; ST.elem = (ElemType*)malloc (sizeof (ElemType) * ST.TableLen); int i; srand (time (NULL )); for (i = 0 ; i < ST.TableLen; i++) { ST.elem[i] = rand () % 100 ; } } void ST_print (SSTable ST) { for (int i = 0 ; i < ST.TableLen; i++) { printf ("%3d" , ST.elem[i]); } printf ("\n" ); } int BinarySearch (SSTable L, ElemType key) { int low=0 ; int high=L.TableLen-1 ; int mid; while (low<=high) { mid=(low+high)/2 ; if (key>L.elem[mid]) { low=mid+1 ; } else if (key<L.elem[mid]) { high=mid-1 ; }else { return mid; } } return -1 ; } int compare (const void *left, const void *right) { return *(int *)left-*(int *)right; } int main () { SSTable ST; ST_Init (ST,10 ); ST_print (ST); qsort (ST.elem,ST.TableLen,sizeof (ElemType),compare); ST_print (ST); ElemType key; printf ("please input search key:\n" ); scanf ("%d" ,&key); int pos=BinarySearch (ST,key); if (pos!=-1 ) { printf ("find key %d\n" ,pos); }else { printf ("not find\n" ); } return 0 ; }
3、二叉排序树原理及建树 二叉排序树满足①左子树非空,左子树结点小于根节点②右子树非空,右子树结点大于根节点③左右子树也是一颗二叉排序树
下面有递归创建和非递归创建的代码,不难理解,思路简单容易上手。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 #include <stdio.h> #include <stdlib.h> typedef int KeyType;typedef struct BSTNode { KeyType key; struct BSTNode *lchild,*rchild; }BSTNode,*BiTree; int BST_Insert1 (BiTree &T,KeyType k) { if (NULL ==T) { T=(BiTree)malloc (sizeof (BSTNode)); T->key=k; T->lchild=T->rchild=NULL ; return 1 ; } else if (k==T->key) return 0 ; else if (k<T->key) return BST_Insert1 (T->lchild,k); else return BST_Insert1 (T->rchild,k); } int BST_Insert (BiTree& T,KeyType k) { BiTree TreeNew= (BiTree)calloc (1 ,sizeof (BSTNode)); TreeNew->key=k; if (NULL ==T) { T=TreeNew; return 1 ; } BiTree p=T,parent; while (p) { parent=p; if (k>p->key) { p=p->rchild; }else if (k<p->key) { p=p->lchild; }else { return 0 ; } } if (k>parent->key) { parent->rchild=TreeNew; }else { parent->lchild=TreeNew; } return 1 ; } void Creat_BST (BiTree& T,KeyType* str,int len) { int i; for (i=0 ;i<len;i++) { BST_Insert (T,str[i]); } } void InOrder (BiTree T) { if (T!=NULL ) { InOrder (T->lchild); printf ("%3d" ,T->key); InOrder (T->rchild); } } BiTree BST_Search (BiTree T,KeyType k,BiTree &parent) { parent=NULL ; while (T!=NULL &&k!=T->key) { parent=T; if (k>T->key) { T=T->rchild; }else { T=T->lchild; } } return T; } int main () { BiTree T=NULL ; KeyType str[7 ]={54 ,20 ,66 ,40 ,28 ,79 ,58 }; Creat_BST (T,str,7 ); InOrder (T); printf ("\n" ); BiTree search,parent; search=BST_Search (T,40 ,parent); if (search) { printf ("find key %d\n" ,search->key); }else { printf ("not find\n" ); } return 0 ; }
4、二叉排序树删除
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 //这个书上没有二叉排序树删除代码--考大题没那么高 void DeleteNode(BiTree &root,KeyType x) { if(NULL==root) { return; } if(root->key>x)//当前结点大于要删除的结点,往左子树找 { DeleteNode(root->lchild,x); }else if(root->key<x)//当前结点小于要删除的结点,往右子树找 { DeleteNode(root->rchild,x); }else{//找到了要删除的结点 if(root->lchild==NULL)//左子树为空,右子树直接顶上去 { BiTree tempNode=root; root=root->rchild; free(tempNode); }else if(root->rchild==NULL)//右子树为空,左子树直接顶上去 { BiTree tempNode=root; root=root->lchild; free(tempNode); }else{//两边都不为空 //一般的删除策略是左子树的最大数据 或 右子树的最小数据 // 代替要删除的节点(这里采用查找左子树最大数据来代替,最大数据是左子树的最右结点) BiTree tempNode=root->lchild; while(tempNode->rchild!=NULL) { tempNode=tempNode->rchild; } root->key=tempNode->key;//把tempNode对应的值替换到要删除的值的位置上 DeleteNode(root->lchild,tempNode->key);//在左子树中找到tempNode的值,把其删除 } } }
5、真题
42.(15 分)一个长度为 L (L ≥1)的升序序列 S,处在第 [L /2]个位置的数称为 S 的中位数。例如,若序列 S1 = (11, 13, 15, 17, 19),则 S1 的中位数是 15,两个序列的中位数是含它们所有元素的升序序列的中位数。例如,若 S2 = (2, 4, 6, 8, 20),则 S1 和 S2 的中位数是 11。 现在有两个等长升序序列 A 和 B,试设计一个在时间和空间两方面都尽可能高效的算法,找出 两个序列 A 和 B 的中位数。要求:
(1)给出算法的基本设计思想。 (2)根据设计思想,采用 C、C++或 Java 语言描述算法,关键之处给出注释。
(3)说明你所设计算法的时间复杂度和空间复杂度。
这个题目所考察的内容是二分查找,但是有两个数组,是双数组的二分查找,是一道非常经典的题目。因为空间尽可能高效,因此我们不能够去再搞一个大数组,把两个数组合并到一 起,这样得分会非常低。 (1)算法的基本设计思想如下:
分别求出序列 A 和 B 的中位数,设为 a 和 b,求序列 A 和 B 的中位数过程如下: (1)若 a=b,则 a 或 b 即为所求中位数,算法结束。 (2)若 a<b,则舍弃序列 A 中较小的一半,同时舍弃序列 B 中较大的一半,要求舍弃的长度相等; (3)若 a>b,则舍弃序列 A 中较大的一半,同时舍弃序列 B 中较小的一半,要求舍弃的长度相等; 在保留的两个升序序列中,重复(1)(2)(3),直到序列中只含一个数,较小者是中位数。
我的代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 #include <iostream> int MidSearch (int * A,int * B,int n) { int s1 = 0 , d1 = n - 1 , m1, s2 = 0 , d2 = n - 1 , m2; while (s1!=d1||s2!=d2) { m1 = (s1 + d1) / 2 ; m2 = (s2 + d2) / 2 ; if (A[m1]==B[m2]) { return A[m1]; }else if (A[m1]<B[m2]) { if ((s1 + d1) % 2 == 0 ) { s1=m1; d2=m2; }else { s1=m1+1 ; d2=m2; } }else { if ((s1 + d1) % 2 == 0 ) { d1=m1; s2=m2; }else { d1=m1; s2=m2+1 ; } } } return A[s1] < B[s2] ? A[s1] : B[s2]; } int main () { int A[] = { 11 ,13 ,15 ,17 ,19 }; int B[] = { 2 ,4 ,6 ,8 ,20 }; int mid = MidSearch (A, B, 5 ); printf ("mid=%d\n" , mid); return 0 ; }