动态查找树 || 键树的c++实现(双链树)

概念:

键树又称为数字查找树,树中的每个结点中不是包含一个或几个关键字,而是只含有组成关键字的符号。例如,若关键字为数值,则结点中只包含一个数位;若关键字为单词,则结点中只包含一个字母字符。这种树会给某种类型关键字的表的查找带来方便。

举例:

{CAI,CAO,LI,LAN,CHA,CHANG,WEN,CHAO,YUN,YANG,LONG,WANG,ZHAO,LIU,WU,CHEN}

我们先针对首字母将其分配:

  • {CAI,CAO,CHA,CHANG,CHAO,CHEN}

  • {WEN,WANG,WU}

  • {ZHAO}

  • {LI,LAN,LONG,LIU}

  • {YUN,YANG}

然后对其中4个关键字大于1的子集再按照第二个字符不同进行分割,直到分割到每个子集包含一个关键字为止。如下图所示:

动态查找树 || 键树的c++实现(双链树)
这种键数的查找速度和HashTable基本相当,但是内存用量却只有HashTable的一半不到。这个对于大容量的数据查找还是一种可行的方法。比如计费系统中的用户资料在计费过程中使用非常频繁,如果id作为关键字的键树的话,会大大提高查询速度。

c++实现:

  • hpp:
//
//  DLTree.hpp
//  DLTree
//
//  Created by peiyu wang on 2019/3/26.
//  Copyright © 2019 peiyu wang. All rights reserved.
//

#ifndef DLTree_hpp
#define DLTree_hpp

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <vector>
using namespace std;

/* 类型定义 */
typedef enum {LEAF, BRANCH} NodeKind;

typedef string KeyType;
typedef char Record;
struct DLTNode
{
    NodeKind kind;
    char symbol; //存储关键字的第一个字符
    DLTNode *next; //指向兄弟结点
    union
    {
        Record *infoptr; //叶子结点指针
        DLTNode *first; //分支结点的孩子链指针
    }Ptr;
};

typedef DLTNode *DLTree;

/* 函数列表 */
// 创建树
int CreateDLTree(DLTree &DT);
// 查找返回指向key的指针
Record* SearchDLTree(DLTree DT, KeyType key);
// 将关键字key插入到双链树中
int InsertDLTree(DLTree &DT, KeyType key);
//输出双链树中关键字
void PrintKeys(DLTree DT);

#endif /* DLTree_hpp */

  • cpp
//
//  DLTree.cpp
//  DLTree
//
//  Created by peiyu wang on 2019/3/26.
//  Copyright © 2019 peiyu wang. All rights reserved.
//

#include "DLTree.hpp"
#include <stack>
// 创建树
int CreateDLTree(DLTree &DT)
{
    DT = new DLTNode;
    DT->kind = BRANCH;
    DT->symbol = '\0';
    DT->next = NULL;
    DT->Ptr.first = NULL;
    KeyType tmp = "";
    int n = 0;
    cout << "请输入你想输入字符串个数:" << endl;
    cin >> n;
    cout << "请输入你想输入的字符串:" << endl;
    while (n--)
    {
        cin >> tmp;
        //cout << tmp.length();
        InsertDLTree(DT, tmp);
    }
    return 1;
}

// 查找返回指向key的指针
Record* SearchDLTree(DLTree DT, KeyType key)
{
    DLTree p = DT->Ptr.first;
    int i = 0;
    while (p && i < key.length())
    {
        while (p && p->symbol < key[i])
        {
            p = p->next;
        }
        if (p && p->symbol == key[i])
        {
            p = p->Ptr.first;
            i++;
        }
        else
        {
            p = NULL;
        }
    }
    if (p && p->kind == LEAF)
    {
        return p->Ptr.infoptr;
    }
    return NULL;
}

// 将关键字key插入到双链树中
int InsertDLTree(DLTree &DT, KeyType key)
{
    DLTree p = DT;
    DLTree q = DT->Ptr.first;
    DLTNode *tmp = NULL;
    int i = 0;
    while (i < key.length())
    {
        while (q && q->symbol < key[i])
        {
            p = q;
            q = q->next;
        }
        if (q && q->symbol == key[i])
        {
            p = q;
            q = q->Ptr.first;
            i++;
        }
        else
        {
            tmp = new DLTNode;
            tmp->kind = BRANCH;
            tmp->symbol = key[i];
            tmp->Ptr.first = NULL;
            tmp->next = NULL;
            if (p->Ptr.first == q)
            {
                p->Ptr.first = tmp;
                tmp->next = q;
            }
            else
            {
                p->next = tmp;
                tmp->next = q;
            }
            p = tmp;
            i++;
            while (i < key.length())
            {
                tmp = new DLTNode;
                tmp->kind = BRANCH;
                tmp->symbol = key[i];
                tmp->Ptr.first = NULL;
                tmp->next = NULL;
                p -> Ptr.first = tmp;
                p = p->Ptr.first;
                i++;
            }
            tmp = new DLTNode;
            tmp->kind = LEAF;
            tmp->symbol = '$';
            char *t_c = new char[key.length() + 1];
            tmp->Ptr.infoptr = strcpy(t_c, key.c_str());
            tmp->next = NULL;
            p->Ptr.first = tmp;
            p = p->Ptr.first;
            i++;
        }
    }
    
    return 1;
}

//输出双链树中关键字
void PrintKeys(DLTree DLT)
{
    if(DLT)
    {
        if(DLT->symbol=='\0')
            PrintKeys(DLT->Ptr.first);
        else if(DLT->symbol=='$')
            cout << DLT->Ptr.infoptr << endl;
        else
        {
            PrintKeys(DLT->Ptr.first);
        }
        PrintKeys(DLT->next);
    }
}

  • main:
//
//  main.cpp
//  DLTree
//
//  Created by peiyu wang on 2019/3/26.
//  Copyright © 2019 peiyu wang. All rights reserved.
//

#include <iostream>
#include "DLTree.hpp"
int main(int argc, const char * argv[]) {
    DLTree DT = NULL;
    CreateDLTree(DT);
    PrintKeys(DT);
    char *k = NULL;
    k = SearchDLTree(DT, "li");
    if (k)
        cout << "OK" << endl;
    else
        cout << "No";
    return 0;
}