[关闭]
@yanglt7 2018-10-21T15:48:37.000000Z 字数 6946 阅读 667

10_查找算法

数据结构和算法


10.1 静态查找和动态查找

10.2 查找结构

10.3 顺序查找

  1. // 顺序查找。a为要查找的数组,n为要查找的数组的长度,key为要查找的关键字
  2. int Sq_Search(int *a, int n, int key)
  3. {
  4. int i;
  5. for( i=1; i <= n; i++ )
  6. {
  7. if( a[i] == key )
  8. {
  9. return i;
  10. }
  11. }
  12. return 0;
  13. }
  14. // 顺序查找优化方案,a为要查找的数组,n为要查找的数组的长度,key为要查找的关键字
  15. int Sq_Search(int *a, int n, int key)
  16. {
  17. int i = n;
  18. a[0] = key;
  19. while( a[i] != key )
  20. {
  21. i--;
  22. }
  23. return i;
  24. }

10.4 插值查找

  1. // 插值查找
  2. #include <stdio.h>
  3. int bin_search(int str[], int n, int key)
  4. {
  5. int low, high, mid;
  6. low = 0;
  7. high = n-1;
  8. while( low <= high )
  9. {
  10. mid = low + (key - a[low]/a[high] - a[low]) * (high-low); // 插值查找的唯一不同点
  11. if( str[mid] == key )
  12. {
  13. return mid;
  14. }
  15. if( str[mid] < key )
  16. {
  17. low = mid + 1;
  18. }
  19. if( str[mid] > key )
  20. {
  21. high = mid -1;
  22. }
  23. }
  24. return -1;
  25. }
  26. int main()
  27. {
  28. }

10.5 斐波那契(黄金比例)查找

10.6 线性索引查找

10.6.1 稠密索引

下标 关键码 指针
0 5
1 12
2 26
3 36
4 55
5 88

10.6.2 分块索引

索引表 25 58 88 各块内的最大关键字
各块内的起始地址字
列表 18 14 12 25 8 28 32 45 36 58 60 88 71
0 1 2 3 4 5 6 7 8 9 10 11 12

10.6.3 倒排索引

10.7 二叉排序树

10.7.1 二叉排序树的查找操作

  1. // 二叉树的二叉链表结点结构定义
  2. typedef struct BiTNode
  3. {
  4. int data;
  5. struct BiTNode *lchild, *rchild;
  6. } BiTNode, *BiTree;
  7. // 递归查找二叉排序树 T 中是否存在 key
  8. // 指针 f 指向 T 的双亲,其初始值调用值为 NULL
  9. // 若查找成功,则指针 p 指向该数据元素结点,并返回 TRUE
  10. // 否则指针 p 指向查找路径上访问的最后一个结点,并返回FALSE
  11. Status SearchBST(BiTree T, int key, BiTree f, BiTree *p)
  12. {
  13. if( !T ) // 查找不成功
  14. {
  15. *p = f;
  16. return FALSE;
  17. }
  18. else if( key == T->data ) // 查找成功
  19. {
  20. *p = T;
  21. return TRUE;
  22. }
  23. else if( key < T->data )
  24. {
  25. return SearchBST( T->lchild, key, T, p ); // 在左子树继续查找
  26. }
  27. else
  28. {
  29. return SearchBST( T->rchild, key, T, p ); // 在右子树继续查找
  30. }
  31. }

10.7.1 二叉排序树的插入操作

  1. // 当二叉排序树 T 中不存在关键字等于 key 的数据元素时,
  2. // 插入 key 并返回 TRUE, 否则返回 FALSE
  3. Status InsertBST(BiTree *T, int key)
  4. {
  5. BiTree p, s;
  6. if( !SearchBST(*T, key, NULL, &p) )
  7. {
  8. s = (BiTree)malloc(sizeof(BiTNode));
  9. s->data = key;
  10. s->lchild = s->rchild = NULL;
  11. if( !p )
  12. {
  13. *T = s; // 插入 s 为新的根结点
  14. }
  15. else if( key < p->data )
  16. {
  17. p->lchild = s; // 插入 s 为左孩子
  18. }
  19. else
  20. {
  21. p->rchild = s; // 插入 s 为右孩子
  22. }
  23. return TRUE;
  24. }
  25. else
  26. {
  27. return FALSE; // 树中已有关键字相同的结点,不再插入
  28. }
  29. }

10.7.3 二叉排序树的删除操作

  1. Status DeleteBST(BiTree *T, int key)
  2. {
  3. if( !*T )
  4. {
  5. return FALSE; // 该元素为空,非空为真,找不到这个元素
  6. }
  7. else
  8. {
  9. if( key == (*T)->data )
  10. {
  11. return Delete(T);
  12. }
  13. else if( key < (*T)->data )
  14. {
  15. return DeleteBST( &(*T)->lchild, key );
  16. }
  17. else
  18. {
  19. return DeleteBST( &(*T)->rchild, key );
  20. }
  21. }
  22. }
  23. Status Delete(BiTree *p)
  24. {
  25. BiTree q, s;
  26. if( (*p)->rchild == NULL )
  27. {
  28. q = *p;
  29. *p = (*p)->lchild;
  30. free(q);
  31. }
  32. else if( (*p)->lchild == NULL )
  33. {
  34. q = *p;
  35. *p = (*p)->rchild;
  36. free(q);
  37. }
  38. else
  39. {
  40. q = *p;
  41. s = (*p)->lchild;
  42. while( s->rchild )
  43. {
  44. q = s;
  45. s = s->rchild;
  46. }
  47. (*p)->data = s->data;
  48. if( q != *p ) // q 没有右子树
  49. {
  50. q->rchild = s->lchild;
  51. }
  52. else
  53. {
  54. q->lchild = s->lchild;
  55. }
  56. free(s);
  57. }
  58. return TRUE;
  59. }

10.8 平衡二叉排序树

10.8.1 平衡二叉排序树的实现原理

  1. #define LH 1
  2. #define EH 0
  3. #define RH -1
  4. typedef struct BiTNode
  5. {
  6. int data;
  7. int bf; // balance factor
  8. struct BiTNode *lchild, *rchild;
  9. } BiTNode, *BiTree;
  10. void R_Rotate(BiTree *p)
  11. {
  12. BiTree L;
  13. L = (*p)->lchild;
  14. (*p)->lchild = L->rchild;
  15. L->rchild = (*p);
  16. *p = L;
  17. }
  18. void LeftBalance(BiTree *T)
  19. {
  20. BiTree L, Lr;
  21. L = (*T)->lchild;
  22. switch( L->bf )
  23. {
  24. case LH:
  25. (*T)->bf = L->bf = EH;
  26. R_Rotate(T);
  27. break;
  28. case RH:
  29. Lr = L->rchild;
  30. switch( Lr->bf )
  31. {
  32. case LH:
  33. (*T)->bf = RH;
  34. L->bf = EH;
  35. break;
  36. case EH:
  37. (*T)->bf = L->bf = EH;
  38. break;
  39. case RH:
  40. (*T)->bf = EH;
  41. L->bf = LH;
  42. break;
  43. }
  44. Lr->bf = EH;
  45. L_Rotate( &(*T)->lchild );
  46. R_Rotate(T);
  47. }
  48. }
  49. int InsertAVL(BiTree *T, int e, int *taller)
  50. {
  51. if( !*T )
  52. {
  53. *T = (BiTree)malloc(sizeof(BiTNode));
  54. (*T)->data = e;
  55. (*T)->lchild = (*T)->rchild = NULL;
  56. (*T)->bf = EH;
  57. *taller = TRUE;
  58. }
  59. else
  60. {
  61. if( e == (*T)->data )
  62. {
  63. *taller = FALSE;
  64. return FALSE;
  65. }
  66. if( e < (*T)->data )
  67. {
  68. if( !InsertAVL(&(*T)->lchild, e, taller) )
  69. {
  70. return FALSE;
  71. }
  72. if( *taller )
  73. {
  74. switch( (*T)->bf )
  75. {
  76. case LH:
  77. LeftBalance(T);
  78. *taller = FALSE;
  79. break;
  80. case EH:
  81. (*T)->bf = LH;
  82. *taller = TRUE;
  83. break;
  84. case RH:
  85. (*T)->bf = EH;
  86. *taller = FALSE;
  87. break;
  88. }
  89. }
  90. }
  91. else
  92. {
  93. if( !InsertAVL(&(*T)->rchild, e, taller) )
  94. {
  95. return FALSE;
  96. }
  97. if( *taller )
  98. {
  99. switch( (*T)->bf )
  100. {
  101. case LH:
  102. (*T)->bf = EH;
  103. *taller = FALSE;
  104. break;
  105. case EH:
  106. (*T)->bf = RH;
  107. *taller = TRUE;
  108. break;
  109. case RH:
  110. RightBalance(T);
  111. *taller = FALSE;
  112. break;
  113. }
  114. }
  115. }
  116. }
  117. }

10.9 多路查找树(Multi-way search tree)

10.9.1 2-3树定义

10.9.2 2-3树的插入原理

10.9.3 2-3树的删除原理

10.9.4 2-3-4树

10.9.5 B树

10.10 散列表(哈希表)查找

10.10.1 散列表的查找步骤

10.11 散列函数的构造方法

10.11.1 数字分析法

10.11.2 平方取中法

10.11.3 折叠法

10.11.4 除留余数法

下标 0 1 2 3 4 5 6 7 8 9 10 11
关键字 12 25 38 15 16 29 78 67 56 21 22 47

10.11.5 随机数法

10.11.6 视不同的情况采用不同的散列函数

10.12 处理散列冲突的方法

10.12.1 开放定址法

下标 0 1 2 3 4 5 6 7 8 9 10 11
关键字 12 25 37 15 16 29 48 67 56 34 22 47

10.12.2 再散列函数法

10.12.3 链地址法

10.12.4 公共溢出区法

10.13 散列表查找的代码实现

  1. #define HASHSIZE 12
  2. #define NULLKEY -32768
  3. typedef struct
  4. {
  5. int *elem; // 数据元素的基址,动态分配数组
  6. int count; // 当前数据元素的个数
  7. } HashTable;
  8. void InitHashTable(HashTable *H)
  9. {
  10. H->count = HASHSIZE;
  11. H->elem = (int *)malloc(HASHSIZE * sizeof(int));
  12. if( !H->elem )
  13. {
  14. return -1;
  15. }
  16. for( i=0; i < HASHSIZE; i++ )
  17. {
  18. H->elem[i] = NULLKEY;
  19. }
  20. return 0;
  21. }
  22. // 使用除留余数法
  23. int Hash(int key)
  24. {
  25. return key % HASHSIZE;
  26. }
  27. // 插入关键字到散列表
  28. void InsertHash(HashTable *H, int key)
  29. {
  30. int addr;
  31. addr = Hash(key);
  32. while( H->elem[addr] != NULLKEY ) //如果不为空,则冲突出现
  33. {
  34. addr = (addr + 1) % HASHSIZE;
  35. }
  36. H->elem[addr] = key;
  37. }
  38. // 散列表查找关键字
  39. int SearchHash(HashTable H, int key, int *addr)
  40. {
  41. *addr = Hash(key);
  42. while( H.elem[*addr] != key )
  43. {
  44. *addr = (*addr + 1) % HASHSIZE;
  45. if( H.elem[*addr] == NULLKEY || *addr == Hash(key) )
  46. {
  47. return -1;
  48. }
  49. }
  50. return 0;
  51. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注