查找算法及二叉平衡树

查找的分类:
1.静态查找
2.动态查找
3.哈希查找

1.1顺序查找法

//应用范围:顺序表或线性链表表示的表,表内元素之间无序。
// 在数组arr中查找等于k的元素,若找到,则函数返回该元素的位置,否则返回0
//平均查找长度:ASL = 1/n∑(n-i+1) = ½(n+1)
int SeqSearch(int arr*, int key)
{
    int i ;
    for(i = 0; i < sizeof(arr)/sizeof(arr[0]); i++)
    {
        if(arr[i] == key)
        {
            return i;
        }
    }
    return 0;
}

1.2二分(折半)查找法

//前提:顺序存储结构且元素有序排列
//平均查找长度:ASL = log2(n+1) - 1
int BinSearch(int *a,int n,int key)
{
    int low = 0;
    int high = n-1;
    while(low<high)
    {
        int mid = (low+high)/2;
        if(a[mid] == key)
        {
              return mid;
        }
        else if(a[mid]>key)
        {
             high = mid-1;
        }
        else
            low = mid+1;
    }
    return -1;
}

2.1
二叉排序树
定义 :
二叉排序树(Binary Sort Tree)又称二叉查找树,是一种特殊的二叉树。
性质:
(1)若左子树不空,则左子树中所有结点的值均小于它的根结点的值;
(2)若右子树不空,则右子树中所有结点的值均大于它的根结点的值;
(3)左、右子树也分别为二叉排序树;
(4)中序遍历(LDR)后为递增序列.

插入算法:
1.若二叉树为空。则首先单独生成根结点。
2.若二叉树非空,则将插入值与二叉排序树根结点的关键字进行比较:
a.如果key的值等于根结点的值,则停止插入;
b.如果key的值小于根结点的值,则将结点插入左子树;
c.如果key的值大于根结点的值,则将结点插入右孩子。
注意:新插入的结点总是叶子结点

//时间复杂度仍为O(log2n)
void InsertBST(BSTree **root,ElemType key)
{
       BSTree* s;
       if((*root)==NULL)
       {
                s = (BSTree*)malloc(sizeof(BSTree));   /*申请新结点*/
      s->data = key;
      s->lchild = NULL;
      s->rchild = NULL;
      *root = s;
       }
      else if(key>(*root)->data)       /*插入右子树*/
               InsertBST(&(*root)->rchild,key);
      else if(key<(*root)->data)      /*插入左子树*/
               InsertBST(&(*root)->lchild,key);
}

查找算法:
首先将待查关键字key与根结点关键字t进行比较,如果:
a.key=t:则返回根结点地址;
b.key

BSTree* SearchBST(BSTree *root,ElemType key)
{
         if(root == NULL)
       return NULL;
         else if(root->data==key)
       return root;
         else
        {
                  if(root->data>key)   /*在左子树中继续找*/
                           return SearchBST(root->lchild,key);
      else
                          return SearchBST(root->rchild,key);  /*在右子树中继续找*/
       }
}

结点删除算法
设在二叉排序树被删除结点是p,其双亲结点为f。(假设结点p是结点f的左孩子)
情况讨论:
(1) 若p为叶结点,则可直接将其删除:f->lchild = NULL;free(p);
(2) 若p结点只有左子树或只有右子树,则可将p的左子树或右子树直接改为其双亲结点f的左子树:f->lchild = p->lchild;free(p);
(3) 若p既有左子树又有右子树,此时有两种处理方法:
方法1:首先找到p结点在中序序列中的直接前驱结点s,然后将p的左子树改为f的左子树,而将p的右子树改为s的右子树:f->lchild = p->lchild;s->rchild = p->rchild;free(p);
方法2(常用):首先找到p结点在中序序列中的**直接前驱结点**s,然后用s结点的值替代p结点的值,再将s结点删除,原s结点的左子树改为s的双亲结点q的右子树:p->data = s->data;q->rchild = s->lchild;free(s);

void Delete(BSTree **root,int key)
{
   BSTree *p = *root;
   BSTree *f = NULL;
   //查找
   while(p)
   {
       if(p->data == key)
       {
           break;
       }
       else if(p->data > key)
       {
          f = p;
         p = p->lchild;
       }
       else
       {
           f = p;
           p = p->rchild;
       }       
   }
   if(p!=NULL)
   {
       //无左孩子
       if(p->lchild==NULL)
       {
           if(f==NULL)
               *root = p->rchild;
           else if(p==f->lchild)
           {
               f->lchild = p->rchild;
           }
           else if(p==f->rchild)
           {
              f->rchild = p->rchild;
           }
           free(p);
           p = NULL;

       }
       //有左孩子
       else
       {
         BSTree *q = p;
         BSTree *s = p->lchild;
         while(s->rchild!=NULL)
         {
             q = s;
             s = s->rchild;
         }
         if(s == p->lchild)
         {
            q->lchild = s->lchild;
         }
         else
             q->rchild = s->lchild;
         p->data = s->data;
         free(s);
         s = NULL;
       }
   }
}

2.2平衡二叉树
定义:
平衡二叉排序树又称为AV树。一棵平衡二叉排序树或者是空树,或者是具有下列性质的二叉排序树
(1) 左子树与右子树的深度之差的绝对值小于等于1;
(2) 左子树和右子树也是平衡二叉排序树。
知识点:
平衡因子(平衡度):结点的平衡因子是结点的左子树的高度减去右子树的高度。
平衡二叉树:每个结点的平衡因子都为 1、-1、0 的二叉排序树。或者说每个结点的左右子树的高度最多差1的二叉排序树。

平衡种类分析:代码较复杂,图奉上

查找算法及二叉平衡树_第1张图片
右调整(新结点插入在右子树上进行的调整)
1、RR 情况:(插入在的右子树的右子树上)
处理方法和 LL对称
2、RL 情况:(插入在右子树的左子树上)
处理方法与LR对称

3.1 哈希表
基本思想:首先在元素的关键字k和元素的存储的存储位置p之间建立一个对应关系H,使得p = H(k),H称为哈希函数。
在记录的存储地址和它的关键字之间建立一个确定的对应关系;这样,不经过比较,一次存取就能得到元素。

哈希函数的构造方法:
1.直接定址法:
适合于地址集合的大小 = = 关键字集合的大小
2.数字分析法:
适合于能预先估计出全体关键字的每一位上各种数字出现的频度。
3.平方取中法
4.分段叠加法
适合于关键字的数字位数特别多,且每一位上数字分布大致均匀情况。
5.除留余数法
6.随机数法
H(key)=random(key)
适于关键字长度不等的情况

冲突解决方法:
1.开放定址法
也称再散列法,其基本思想是:当关键字key的初始哈希地址H0=H(key)出现冲突时,以H0为基础,产生另一个地址H1,如果H1仍然冲突,再以H1为基础,产生另一个哈希地址H2……..直到找出一个不冲突的地址,将相应元素存入其中。
2.再哈希法
这种方法可以同时构造多个不同的哈希函数:
Hi=RHi(key) i = 1,2,3,…n
当哈希地址H1=RH1(key) 发生冲突时,再计算H2=RH2(key) ……直到冲突不再产生。这种方法不易产生聚集,但增加了计算时间。
3.链地址法
方法:将所有关键字为同义词的记录存储在一个单链表中,并用一维数组存放头指针。
适用于经常进行插入和删除的情况。

你可能感兴趣的:(查找算法)