数据结构-查找

查找

关键词


  1. 关键字
  2. 主关键字
  3. 次关键字

平均查找长度


定义: 需和给定值比较的关键字的个数的期望值,成为查找成功时的平均查找长度

对于有n个关键字的表,其平均查找长度如下:

其中是查找第i个关键字的概率,可知 (个人理解给定值出现在位置i上的概率)

是在i位置查找到目标值时,已经比较过的关键字的个数.

静态查找表


静态查找表的顺序存储结构

typedef struct{
    Elemtype *list;
    int ncount;
}SSTable;

顺序查找的实现

从后往前找,零号位置作为哨兵,这样不用没找一次比较一次,当查找量大于1000的时候,是可以提高一倍效率的.

int search(SSTable &list,Elemtype keyword){
    (list.list)[0]=keyword;
    int i=list.ncount;
    while ((list.list)[i]==keyword) i--;
    return i;
}

性能分析

如果在第一个位置需要查找n次,如果在最后一个位置需要查找1次,于是可以归纳出在第i个位置需要查找n-i+1

一般情况下,出现在每个目标出现在每个位置的概率时相等的,即

tip:上述讨论是忽略了查找不成功的情况的,一般情况下查找不成功的概率确实小的可以忽略不计.

有序表的查找


折半查找算法(实际上就是二分查找)

int search_bin(SSTable &list,Elemtype key){
    int l=1,r=list.ncount;
    while (l<=r>){
        int mid=(l+r)/2;
        if (key==(list.list)[mid]) return mid;
        else if(key>(list.list)[mid]) l=mid+1;
        else r=mid-1;
    }
    return 0;
}

性能分析

  • 通过判定树来分析

  • 有n个节点的树的最大深度是

  • 访问第h层的节点总共需要访问个节点(最坏情况)

二叉树第h层有个节点
h层的二叉树有个节点
等比数列公式:

为了方便计算,假设一个深度为h的满二叉树,此时,并且目标值出现在每个位置的概率是相同的

可以得到:

当n比较大的时候()时,可以近似等于

动态查找树表


动态查找表的特点:表结构本身是在查找过程中动态生成的,即若存在返回索引,不存在插入

二叉排序树(BST)


定义:

二叉排序树或者是一颗空树,或者是符合以下定义的树:
(1)若它的左子树不为空,则左子树上所有的节点均小于根节点上的值
(2)若它的右子树不为空,则右子树上所有的节点均大于根节点上的值
(3)它的左子树和右子树同样是二叉排序树

储存结构:(和二叉树其实是一样的)

typedef struct BiTNode{
    elemtype data;
    struct BiTNode *lchild,*rchild;
}BiTNODE,*BiTree;

查找算法

BiTree search(BiTree root,elemtype key,BiTree &pre,BiTree &p){
    //p是要传给外部的参数
    if (!root) {p=pre;return NULL;} //返回上一个
    if (root->data==key) return root;
    else if(key>root->data) search(root->rchild,key,root);
    else search(root->lchild,key,root,p);
}

插入算法

int add(BiTree &T,elemtype key){
    BiTree temp;
    if (!search(T,key,T,temp)){
        //生成节点
        BiTree newnode=(BiTree)malloc(sizeof(BiTNode));
        *newnode={key,NULL,NULL};
        if (!temp) T=newnode;
        else{
            if (key>T->data) temp->lchild=newnode;
            else temp->rchild=newnode;
        }
    }
    else return -1;
    return 0;
}

删除算法

分为三种
(1)被删除的只有叶子节点
(2)被删除的只有左子树或者右子树
(3)被删除的节点既有左子树又有右子树

(1)将双亲节点的对应的指针域改成空

(2)双亲节点指向被删除节点的对应的左子树或者右子树

(3)可以从左子树操作也可以从右子树操作,这里就以左子树为例.

  1. 找到左子树里面最大的关键字,替换被删除节点
  2. 刚刚用来替换的那个最大的关键字的右子树一定是空的,用(2)处理以下就可以了
int delete_1(BiTree& t,elemtype key){
    BiTree &pre,temp;
    temp=search(T,key,T,pre);
    if (!temp) return -1;
    else{
        if (!(temp->rchild)) {pre->next=temp->left;free(temp);}
        else if(!(temp->lchild)) {pre->next=temp->right;free(temp);}//这里的pre->next指所对应的左子树或者右子树
        else{
            BiTree temp2;
            pre=temp;
            temp2=temp->lchild;
            while (temp2->rchild){pre=temp2; temp2=temp2->rchild;}
            temp->data=temp2->data;
            pre->next=temp2->right;
            free(temp2);
        }
    }
}

tip:这里的代码可能有问题,重点看一下思路吧

conclude: 对于经常需要删除和添加的有序表,使用二叉排序树是比较合适的

查找性能分析

对于不同的插入顺序,构造出来的二叉排序树是不一样的,于是查找的复杂度也是不一样的,于是这里直接给出计算后的平均值

二叉平衡树


定义: 平衡二叉树又称AVL树.它或者是一棵空树,或者是一棵具有如下性质的树:
(1) 它的左子树和右子树都是平衡二叉树
(2) 他的左右子树深度之差的绝对值不超过1

平衡因子

左子树的深度与右子树深度的差值(注意先后顺序)

特点

平衡因子的绝对值不大于1

构造-平衡旋转技术

平衡旋转技只针对最小不平衡子树

平均查找长度在log级别上

4种平衡旋转

  1. LL型,右旋一次,被折下去的那个节点的左子树会空出来,由定义可以知道,被折下去的部分一定是大于左边部分的,于是空出来的位置可以接上折上去的节点的右子树.

  2. RR型,左旋一次,其余原理同LL型是一致的.

  3. LR型

  4. RL型

tip:怎么插入的这个节点其实和如何旋转对应上了

B-树


(待续)

哈希表


你可能感兴趣的:(数据结构-查找)