《大话数据结构》读书笔记(四)
来源:互联网 发布:isp 网络拓扑 编辑:程序博客网 时间:2024/05/21 11:36
第8章 查找(Searching)
查找:根据给定的某个值,在查找表中确定一个字等于给定值的数据元素(或记录)
顺序查找(Sequential Search)
顺序查找又叫线性查找,从表中第一个(或最后一个)记录开始,逐个进行记录的关键字和给定值比。
有序表查找
折半查找(Binary Search)
折半查找的时间复杂度为O(logn)
插值查找(Interpolation Search)
根据要查找的关键字key与查找表中最大最小记录的关键字比较后的查找方法,其核心就在与插值的计算公式。
mid = low+(high-low)*(key-a[low])/(a[high]-a[low])
时间复杂度O(logn)
斐波那契查找(Fibonacci Search)
线性索引查找
线性索引就是将索引项集合组织为线性结构,包括稠密索引、分块索引和倒排索引。
二叉排序树(Binary Sort Tree)
二叉排序树又称二叉查找树。它或者是一棵空树,或者是具有下列性质的二叉树。
1)左子树均小于它的根结构的值。
2)右子树均大于它的根结构的值。
3)它的左右子树也分别为二叉排序树。
二叉树插入操作
二叉排序树删除操作
平衡二叉树(AVL树)
平衡二叉树(Self-Balancing Binary Search Tree 或 Height-Balanced Binary Search Tree),
是一种二叉排序树,其中每一个节点的左子树和右子树的高度差至少等于1.
平衡因子BF(Balance Factor):将二叉树上结点的左子树深度减去右子树深度的值。
平衡二叉树上所有结点的平衡因子只可能是-1、0和1.
平衡二叉树实现算法
右旋操作
左旋操作
左平衡旋转处理
插入实现代码
查找:根据给定的某个值,在查找表中确定一个字等于给定值的数据元素(或记录)
顺序查找(Sequential Search)
顺序查找又叫线性查找,从表中第一个(或最后一个)记录开始,逐个进行记录的关键字和给定值比。
顺序查找的时间复杂度为O(n)
/* 顺序查找,a为数组,n为要查找的数组个数,key为要查找的关键字 */int Sequential_Search(int *a, int n, int key){int i;for(i=1;i<=n;i++){if (a[i] ==key)return i;}return 0;}
/* 有哨兵顺序查找 */int Sequential_Search2(int *a,int n,int key){int i;a[0] = key;i = n;while(a[i] != key){i--;}return i; /* 返回0则说明查找失败 */}
有序表查找
折半查找(Binary Search)
折半查找的时间复杂度为O(logn)
int Binary_Search(int *a, int n, int key){int low,high,mid;low=1;high=n;while(low<=high){mid = (low+high)/2;if(key<a[mid])high = mid-1;else if (key>a[mid])low = mid+1;elsereturn mid;}return 0;}
插值查找(Interpolation Search)
根据要查找的关键字key与查找表中最大最小记录的关键字比较后的查找方法,其核心就在与插值的计算公式。
mid = low+(high-low)*(key-a[low])/(a[high]-a[low])
时间复杂度O(logn)
斐波那契查找(Fibonacci Search)
/* 斐波那契查找 */int Fibonacci_Search(int *a, int n, int key){int low, high, mid, i, k;low =1;high =n;k =0;while(n>F[k]-1) /* 计算n位于斐波那契数列的位置 */k++;for(i=n;i<F[k]-1;i++) /* 将不满的数值补全 */a[i] = a[n];while(low<=high){mid=low+F[k-1]-1; /* 计算当前分隔的下标 */if(key<a[mid]) /* 若查找记录小于当前分隔记录 */{high = mid-1; /* 最高下标调整到分隔下标mid-1处 */k = k-1; /* 斐波那契数列下标减一位 */}else if (key>a[mid]) /* 若查找记录大于当前分隔记录 */{low=mid+1; /* 最低下标调整到分隔下标mid+1处 */k = k-2; /* 斐波那契数列下标减两位 */}else{if (mid<=n)return mid; /* 若相等则说明mid即为查找到的位置 */elsereturn n; /* 若mid>n说明是补全数值,返回n */}return 0;}}/* 斐波那契递归函数 */int Fbi(int i){if (i < 2)return (i==0)? 0 : 1;return Fbi(i-1)+Fbi(i-2);}
线性索引查找
线性索引就是将索引项集合组织为线性结构,包括稠密索引、分块索引和倒排索引。
二叉排序树(Binary Sort Tree)
二叉排序树又称二叉查找树。它或者是一棵空树,或者是具有下列性质的二叉树。
1)左子树均小于它的根结构的值。
2)右子树均大于它的根结构的值。
3)它的左右子树也分别为二叉排序树。
/* 二叉树的二叉链表结点结构定义 */typedef struct BiTNode{int data; struct BiTNode *lchild, *rchild;}BiTNode, *BiTree;
/* 递归查找二叉排序树T中是否存在key *//* 指针f指向T的双亲,其初始调用值为NULL *//* 若查找成功,则指针p指向该数据元素结点,并返回true *//* 否则指针p指向查找路径上访问的最后一个结点并返回false */Status SearchBST(BiTree T, int key, BiTree f, BiTree *p){if (! T){*p = f;return false;}else if (key==T->data){*p = T;return true;}else if (key <T->data)return SearchBST(T->lchild,key,T,p);elsereturn SearchBST(T->rchild,key,T,p);}
二叉树插入操作
/* 当二叉排序树T中不存在关键字等于key的元素时*//* 插入key并返回true,否则返回false*/Status InsertBST(BiTree *T, int key){BiTree p,s;if (!SearchBST(*T,key,NULL,&p)){s = (BiTree) malloc (sizeof(BiTNode));s->data = key;s-lchild = s->rchild = NULL;if (!p)*T = s; /* 插入s为新的根结点 */else if (key<p->data)p->lchild = s;elsep->rchild = s;return true;}elsereturn false;}
二叉排序树删除操作
/* 若二叉排序树T中存在关键字等于key的数据元素时,则删除该数据元素结点,*//* 并返回true,否则返回false */Status DeleteBST(BiTree *T, int key){if (! *T)return false;else{if (key == (*T)->data)return Delete(T);else if (key < (*T)->data)return DeleteBST(& (*T)->lchild,key);elsereturn DeleteBST(& (*T)->rchild,key);}}/* 从二叉排序树中删除结点p,并重接它的左或右子树 */Status Delete(BiTree *p){BiTree q,s;if ((*p)->rchild == NULL) /* 右子树空则只需重接它的左子树 */{q=*p;*p=(*p)->lchild;free(q);}else if ((*p)->lchild == NULL) /* 左子树空则只需重接它的右子树 */{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的右子树 */elseq->lchild = s->lchild; /* 重接q的左子树 */free(s);}return true;}
平衡二叉树(AVL树)
平衡二叉树(Self-Balancing Binary Search Tree 或 Height-Balanced Binary Search Tree),
是一种二叉排序树,其中每一个节点的左子树和右子树的高度差至少等于1.
平衡因子BF(Balance Factor):将二叉树上结点的左子树深度减去右子树深度的值。
平衡二叉树上所有结点的平衡因子只可能是-1、0和1.
平衡二叉树实现算法
/* 二叉树的二叉链表结点结构定义 */typedef struct BiTNode /* 结点结构 */{int data; /* 结点数据 */int bf; /* 结点的平衡因子 */struct BiTNode *lchild, *rchild; /* 左右孩子指针 */}BiTNode, *BiTree;
右旋操作
/* 对以p为根的二叉排序树作右旋处理, *//* 处理之后p指向新的树根结点,即旋转处理之前的左子树的根结点 */void R_Rotate(BiTree *P){BiTree L;L = (*P)->lchild; /* L指向P的左子树根结点 */(*P)->lchild = L->rchild; /* L的右子树挂接为P的左子树 */L->rchild = (*P); *P = L; /* P指向新的根结点 */}
左旋操作
/* 对以p为根的二叉排序树作左旋处理, *//* 处理之后p指向新的树根结点,即旋转处理之前的右子树的根结点 */void R_Rotate(BiTree *P){BiTree R;R = (*P)->rchild; /* R指向P的右子树根结点 */(*P)->rchild = R->lchild; /* R的左子树挂接为P的右子树 */R->lchild = (*P); *P = R; /* P指向新的根结点 */}
左平衡旋转处理
#define LH +1 /* 左高 */#define EH 0 /* 等高 */#define RH -1 /* 右高 *//* 对以指针T所指结点为根的二叉树作左平衡旋转处理 *//* 本算法结束时,指针T指向新的根结点 */void LeftBalance(BiTree *T){BiTree L, Lr;L = (*T)->lchild; /* L指向T的左子树根结点 */switch(L->bf){/* 检查T的左子树的平衡度,并作相应的平衡处理 */case LH: /* 新结点插入在T的左孩子的左子树上,要作单右旋处理 */(*T)->bf = L->bf = EH;R_Rotate(T);break;case RH: /* 新结点插入在T的左孩子的右子树上,要作双旋处理 */Lr = L->rchild; /* Lr指向T的左孩子的右子树根 */switch(Lr->bf) /* 修改T及其左孩子的平衡因子 */{case LH:(*T)->bf = RH;L->bf = EH;break;case EH:(*T)->bf = L->bf = EH;break;case RH:(*T)->bf = EH;L->bf = LH;break;}Lr->bf = EH;L_Rotate(& (*T)->lchild); /* 对T的左子树作左旋平衡处理 */R_Rotate(T); /* 对T作右旋平衡处理 */}}
插入实现代码
/* 若在平衡的二叉排序树T中不存在和e有相同关键字的结点,则插入一个 *//* 数据元素e的新结点并返回1,否则返回0.若因插入而使二叉排序树失去 *//* 平衡,则作平衡旋转处理,布尔变量taller反映T长高与否 */Status InsertAVL(BiTree *T, int e, Status *taller){if (!*T){/* 插入新结点,树“长高”,置taller为true */*T = (BiTree) malloc (sizeof(BiTNode));(*T)->data =e;(*T)->lchild = (*T)->rchild = NULL;(*T)->bf = EH;*taller = true;}else{if (e == (*T)->data){/* 树中已存在和e有相同关键字的结点则不再插入 */*taller = false;return false;}if (e<(*T)->data){/* 应继续在T的左子树中进行搜索 */if (!InsertAVL(&(*T)->lchild,e,taller)) /* 未插入 */return false;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)) /* 未插入 */return false;if (*taller) /* 已插入到T的右子树中且右子树“长高” */{switch((*T)->bf){case LH:(*T)->bf = EH;*taller = false;break;case EH:(*T)->bf = RH*taller = true;break;case RH:RightBalance(T);*taller = false;break;}}}}return true;}
平衡二叉树的查找、插入和删除的时间复杂度都是O(logn)。
多路查找数(B树)
散列表查找(哈希表)
散列函数构造方法
直接定址法
数字分析法
平方取中法
折叠法
除留余数法
f(key) = key mod p (p<=m)
随机数法
f(key) = random(key)
处理散列冲突方法
开放定址法,也称为线性探测法,一旦发生了冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入。
fi(key) = (f(key) + di) MOD m (di=1,2,3,……,m-1)
二次探测法
fi(key) = (f(key) + di) MOD m (di=1^2,-1^2,2^2,-2^2,……,q^2,-q^2,q<=m/2)
在冲突时,对于位移量di采用随机函数计算得到,称为随机探测法
fi(key) = (f(key) + di) MOD m (di是一个随机数列)
再散列函数法
fi(key) = RHi(key) (i=1,2,……,k),其中RHi就是不同的散列函数
链地址法
公共溢出区法
散列表查找实现
#define SUCCESS 1#define UNSUCCESS 0#define HASHSIZE 12 /* 定义散列表长为数组的长度 */#define NULLKEY -32768typedef struct{int *elem; /* 数据元素存储基址,动态分配数组 */int count; /* 当前数据元素个数 */}HashTable;int m = 0; /* 散列表表长,全局变量 *//* 初始化散列表 */Status InitHashTable(HashTable *H){int i;m = HASHSIZE;H->count = m;H->elem = (int *)malloc(m*sizeof(int));for(i=0;i<m;i++)H->elem[i] = NULLKEY;return OK;}/* 散列函数 */int Hash(int key){return key % m; /* 除留余数法 */}/* 插入关键字进散列表 */void InsertHash(HashTable *H, int key){int addr = Hash(key); /* 求散列地址 *//* 开放定址法的线性探测 */while(H->elem[addr] != NULLKEY)addr = (addr+1) %m;H->elem[addr] = key;}/* 散列表查找关键字 */Status SearchHash(HashTable H, int key, int *addr){*addr = Hash(key);while(H.elem[*addr] != key) /* 如果不为空,则冲突 */{*addr = (*addr+1) % m; /* 开放定址法的线性探测 *//* 如果循环回到原点 */if (H.elem[*addr] == NULLKEY || *addr == Hash(key)){return UNSUCCESS; /* 说明关键字不存在 */}}return SUCCESS;}
- 《大话数据结构》读书笔记(四)
- 大话数据结构读书笔记系列(四)栈与队列
- 大话数据结构读书笔记(四)-栈和队列
- 《大话数据结构》读书笔记(一)
- 《大话数据结构》读书笔记(二)
- 《大话数据结构》读书笔记(三)
- 《大话数据结构》读书笔记(五)
- 《大话数据结构》读书笔记(1)
- 《大话数据结构》读书笔记(2)
- 《大话数据结构》读书笔记(一)
- 《大话数据结构》读书笔记(二)
- 《大话数据结构》读书笔记(三)
- 大话数据结构——读书笔记(2)
- 【读书笔记】大话数据结构之 栈(1)
- 大话数据结构读书笔记系列(二)算法
- 大话数据结构读书笔记系列(五)串
- 大话数据结构读书笔记(二)-算法
- 大话数据结构读书笔记(三)-线性表
- Yii-常用-url调用
- 3亿移动用户,是该好好投入android开发了
- android 数据库 SQLite
- Java 调用 C程序 之HelloWorld
- javascript中的apply和call
- 《大话数据结构》读书笔记(四)
- 2013、1、7待看
- 黑马程序员---关于访问控制符的问题:
- Android GestureDetector手势识别类
- 导出Excel--处理标题
- 一个简单的Android进程管理器(初稿)
- 黑马程序员--类的构造函数
- 第一章 Spring 基础介绍
- centos下安装和使用apache