triecnt.cpp

来自「经典c++程序的实现」· C++ 代码 · 共 160 行

CPP
160
字号
// 使用联合实现不同的分支结点和叶结点,triecount.cpp
#include <iostream.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <assert.h>
#include "..\include\book.h"
typedef char ELEM;

typedef ELEM* Attr;
const base = 26;
const start = 'a';

enum Nodetype {leafnode, internal};  // Enumerate possible node types

class TrieNode {       // Generic node class
public:
  Nodetype mytype;       // Stores the type for this particular node
  char symbol;      // Internal node value
  union {
       struct {
          TrieNode* trieptr[base+1];    // Structure for internal node
          int count;   // the number of children
       } intl;
       struct {
           ELEM *data;
           Attr attribute;         // Leaves just store a value
       } leaf;
  };
  TrieNode(const Attr val) // Constructor: leaf
    { mytype = leafnode;  leaf.attribute = val; }
  // Constructor: Internal
  TrieNode(int cnt=0) {
      mytype = internal; intl.count = cnt;
      for (int i=0; i<base+1; i++)
          intl.trieptr[i] = NULL;
  }
  bool isLeaf() { return mytype == leafnode; }
};

void traverse(TrieNode* rt) { // Preorder traversal
  if (rt == NULL) return;
  if (rt->isLeaf()) cout << "Leaf: " << rt->leaf.attribute << "\n";
  else {
	cout << "**" << rt->intl.count << endl;
    // cout << "Internal: " << rt->symbol << "\n";
	for (int i=0; i<base+1; i++)
       traverse(rt->intl.trieptr[i]);
  }
}


// 插入值为'*'的结点到字符树,其中rt为根,q为前驱
// attribute为要插入的属性。
Attr insertLeaf(TrieNode *q, Attr attribute) {
    TrieNode *s;
    s = new TrieNode(attribute);  
    q->intl.trieptr[0] = s;
	q->intl.count++;
    s->leaf.attribute = new char [strlen(attribute)];
    strcpy(s->leaf.attribute, attribute);
    return s->leaf.attribute;
}

// 插入val从k开始的子串到字符树中, q为前驱(q为空是表示新插入当根),
// attribute为要插入的属性。
Attr insertSubtree(TrieNode* &q, ELEM *val, 
                int k, Attr attribute) {
    TrieNode *s;
    int len;
    len = strlen(val);
    s = new TrieNode(0);
    if (q == NULL)
        q = s;
    else {
		q->intl.trieptr[val[k]-start+1] = s;
		q->intl.count++;
	}
    for (int j=k+1; j<len; j++)  {
       s->intl.trieptr[val[j]-start+1] = new TrieNode(0);
	   s->intl.count++;
       s = s->intl.trieptr[val[j]-start+1];
    }
    return insertLeaf(s, attribute); 
}

// 查找双链树中结点,rt为根,val为要找的关键码,返回值为空则查找失败,
// 否则为属性值。
// 查找普通的关键码,关键码并不需要以“*”结尾
Attr trietree_insert(TrieNode *rt, char *val, Attr attribute) {
    int i = 0, len;    TrieNode *p, *q;
    p = rt;  q = NULL;  len = strlen(val);
    while (p != NULL && i < len)  {
        q = p;
        p = p->intl.trieptr[val[i]-start+1];  // 查找关键码的第i位
        i++;
    }
    if (p != NULL)  { 
        q = p;
        p = p->intl.trieptr[0];
        if (p == NULL)
            insertLeaf(q, attribute);
        else  return p->leaf.attribute;  // 存在此关键码
    }
    else return insertSubtree(q, val, i-1, attribute);
	return NULL;
}

// 查找双链树中结点,rt为根,val为要找的关键码,返回值为空则查找失败,
// 否则为属性值。
// 查找普通的关键码,关键码并不需要以“*”结尾
Attr trietree_search(TrieNode* rt, char* val) {
    int i = 0, len;    TrieNode *p, *q;
    p = rt;   len = strlen(val);
    while (p != NULL && i < len)  {
        p = p->intl.trieptr[val[i]-start+1];  // 查找关键码的第i位
        i++;
    }
    if (p != NULL)  { 
        q = p;
        p = p->intl.trieptr[0];
        if (p == NULL)
            return NULL;
        else  return p->leaf.attribute;  // 存在此关键码
    }
    else return NULL;
}

int main()
{
  TrieNode* root;
  char *str;

  root = new TrieNode(0);
  str = "hero";
  trietree_insert(root, str, str);
  str = "aeo";
  trietree_insert(root, str, str);
  str = "here";
  trietree_insert(root, str, str);
  str = "heri";
  trietree_insert(root, str, str);
  /*
  //while (!EOF)  {
  cin >> str;
  while (str[0] != 'X') {
      trietree_insert(root, str, str);
      cin >> str;
  }
  */
  traverse(root);
  str = "hero";
  cout << str;
  if (trietree_search(root, str) != NULL)
	  cout << "OK\n";
  else cout << "NO\n";
  return(0);
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?