初学数据结构---查找

来源:互联网 发布:正整数分解质因数算法 编辑:程序博客网 时间:2024/06/06 01:08

一、基本概念:

1、  列表:由同一类型的数据元素或记录构成的集合----待搜索的数据集合。

1.1  静态查找表:只进行查找操作的查找表。

1.2  动态查找表:除了查找还有插入删除等操作的查找表。

2、  关键字:用来查找的那个数据,可以是数据元素中某个数据项的值。3、  查找:根据关键字在查找表中找到与关键字等值的数据元素并返回或返回其地址的一种算法过程。

4、  算法的平均查找长度:ASL(平均查找长度)=∑ (1---n) P(i)C(i) 

P(i):查找表中第i个记录的概率(个人理解:比较一次正确概率)。 取1/n。c(i):当给定值与表中记录相等时候,已经比较的次数,C(i)随过程不同。

ASL' = 1/2n* ∑ Ci+1/(2n+1)* ∑Ui.

Ui : 第i个事件查找失败时已经比较过得次数。

5、  判定树:可以形象而又直观的反映一个查找算法在查找任意给定值所进行的比较次数的判断树。

6、  相关约定:

6.1  有序表升序排列。

6.2  平均查找等概率。

二、基于线性表的查找:1、  顺序查找:(1)思想:逐个比较,直到找到或者查找失败。(2)时间复杂度:T(n) = O(n)。(3)空间复杂度:S(n) = O(n)。

(4)程序: 

int Seq_Search(RecordList l, KeyType key)  {           l.r[0].key = k;           i = l.length;           while(l.r[i].key != k)                     i--;           return  i;  }  
2、  折半查找:


(1)思想:又称二分查找,对于已经按照一定顺序排列好的列表,每次都用关键字和中间的元素对比,然后判断是在前部分还是后部分还是就是中间的元素,然后继续用关键字和中间的元素对比。


(2)时间复杂度:O(logN)


(3)空间复杂度:O(0)


(4)程序:

Int BinSrch(RecordList l, KeyType k)  {           low = 1;           high = l.length;           while(low <= high)           {                mid = (low + high) / 2;                if(k == l.r[mid].key)                     return mid;                else if(k < l.r[mid].key)                     high = mid -1;                else                     low = mid + 1;           }           return 0;  }  

3、  分块查找:


(1)思想:把无序的列表分成若干子块(子表),然后建立一个索引表,记录每个子块中的某个关键字(最大的数或是最小的数),然后用关

键字和这个索引表进行对比。该索引表还存储子块的起始位置,所以可以使用折半查找或者顺序查找确定关键字所在的子块位置。进入子块

后,使用顺序查找查找。


(2)时间复杂度:(没要求)


(3)空间复杂度:(没要求)


(4)程序:(略)


三、基于树的查找:


1、  二叉排序树:


(1)思想:二叉排序树:①若它的左子树非空,则左子树上所有节点的值均小于它的根节点的值;②若它的右子树非空,则右子树上所有结点的值均大于(或大于等于)它的根节点的值;③它的左、右子树也分别为二叉排序树。查找的时候,中序遍历二叉树,得到一个递增有序序列。查找思路类似于折半查找。


(2)时间复杂度:插入一个节点算法的O(㏒n),插入n个的总复杂度为O(n㏒n)。


(3)空间复杂度:


(4)程序:

查找:

typedef struct BiTNode{    int data;    struct BiTNode *lchild, *rchild;}BiTNode, *BiTree;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->rchild, key, T, p);    }else{        return SearchBST(T->lchild, key, T, p);    }}

插入:

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;        }else if(key > p->data){            p->rchild = s;        }else{            p->lchild = s;        }        return TRUE;    }else{        return FALSE;    }}

删除:

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;        if(q != *p){            q->rchild = s->lchild;        }else{            q->lchild = s->lchild;        }        free(s);    }}

删除节点:

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);        }else{            return DeleteBST(&(*T)->rchild, key);        }    }}

删除操作有四种情况:


1. 要删除的结点是叶子结点。


2. 要删除的结点有左孩子。


3. 要删除的结点有右孩子。


4. 要删除的结点有左右孩子。



2、  平衡二叉排序树:


(1)思想:首先它也是二叉排序树,但是还要具有如下性质:①左子树和右子树的深度之差的绝对值小于等于1;②左子树和右子树也是平衡二叉树。


(2)时间复杂度:


(3)空间复杂度:


(4)程序:

typedef struct BiTNode{    int data;    int bf;        // 结点的平衡因子    struct BiTNode *lchild, *rchild;}BiTNode, *BiTree;
(5)操作:
PS:平衡二叉树上所有结点的平衡因子只可能是-1、0和1。只要二叉树上有一个结点的平衡因子的绝对值大于1,则该二叉树就是不平衡的




代码:不要求。


3、  B_树:多路查找树(multi-way search tree)的每一个结点的孩子数可以多于两个,且每一个结点
处可以存储多个元素。元素之间存在某种特定的排序关系。


(1)思想: 它或者是一棵空树;或者是具有下列性质的二叉树:

  (1)若左子树不空,则左子树上所有结点的值均小于左子树所在树的根结点的值;


  (2)若右子树不空,则右子树上所有结点的值均大于右子树所在树的根结点的值;

  (3)左、右子树也分别为二叉排序树;

(2)时间复杂度:

(3)B树的插入:


首先执行查找算法,找出被插结点的父亲结点。

  判断被插结点是其父亲结点的左儿子还是右儿子。将被插结点作为叶子结点插入。

  若二叉树为空。则首先单独生成根结点。

  注意:新插入的结点总是叶子结点,所以算法复杂度是O(h)。

(4)B树的删除:

  如果删除的结点没有孩子,则删除后算法结束;

  如果删除的结点只有一个孩子,则删除后该孩子取代被删除结点的位置;

  如果删除的结点有两个孩子,则选择该结点的后继结点(该结点右孩子为根的树中的左子树中的值最小的点)作为新的根,同时在该后

继结点开始,执行前两种删除算法,删除算法结束。


5、B+树

一棵m阶的B+树满足下列条件:

(1)每个结点最多m个孩子。

(2)除根结点和叶子结点外,其它每个结点至少有ém/2ù个孩子。

(3)根结点至少有两个孩子。

(4)所有的叶子结点在同一层,且包含了所有关键字信息。

(5)有k个孩子的分支结点包含k个关键字。



四、计算式查找:


1、  哈希查找:

(1)思想:首先在元素的关键字k和元素的存储位置p之间建立一个对应关系H,使得p=H(k),H称为哈希函数。创建哈希表时,把关键字为k的

元素直接存入地址为H(k)的单元;以后当查找关键字为k的元素时,再利用哈希函数计算出该元素的存储位置p=H(k),从而达到按关键字直接

存取元素的目的。难点在于处理冲突的方式:①开放定址法②再哈希法③链地址法④建立公共溢出区。

(2)时间复杂度:

(3)空间复杂度:

(4)程序:

查找:

void SearchHash(HashTable *H, int key){    int addr = Hash(key);    while(H->elem[addr] != key){        addr = (addr + 1) % m;        if(H->elem[addr] != key  || addr == Hash(key))        {            return UNSUCCESS;        }    }    return SUCCESS;}

结构:

#define SUCCESS 1#define UNSUCCESS 0#define HASHSIZE 12#define NULLKEY -32768typedef struct {    int *elem;        // 数据元素存储基址    int count;        // 当前数据元素个数}HashTable;int m = 0;            // 散列表表长,全局变量