trinhert.cpp

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

CPP
184
字号
// 用不同的类实现分支结点和叶结点trherit.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* Attr;
typedef char* Keytype;

class CharTreeNode {                   // Node base class
public:
  char symbol;                     // symbol of character tree
  // isLeaf is a "pure" virtual function, which means CharTreeNode
  // contains no definition.  Each derived class must define isLeaf.
  virtual bool isLeaf() = 0;
};

class LeafNode : public CharTreeNode { // Leaf node subclass
private:
  Attr attribute;                          // attribute value
  CharTreeNode *right;
public:
  LeafNode(const Attr& val, CharTreeNode *rightsib = NULL) { // Constructor
     attribute = val; symbol = '*';
     right = rightsib;
  }
  bool isLeaf() { return TRUE; }     // Version for this subclass
  Attr& value() { return attribute; }      // Return node value
  CharTreeNode* rightchild() { return right; } // Right child
};

class IntlNode : public CharTreeNode { // Internal node subclass
private:
  CharTreeNode* left;                  // Left child
  CharTreeNode* right;                 // Right child
public:
  IntlNode(const char& sym, CharTreeNode* l, CharTreeNode* r)
    { symbol = sym; left = l; right = r; } // Constructor
  bool isLeaf() { return FALSE; }    // Version for this subclass
  CharTreeNode* leftchild() { return left; }   // Left child
  CharTreeNode* rightchild() { return right; } // Right child
  void setleft(CharTreeNode* leftval) { left = leftval; } // set left child
  void setright(CharTreeNode* rightval) { right = rightval; } // set right
  char value() { return symbol; }          // Value
};

void traverse(CharTreeNode *rt) {      // Preorder traversal
  if (rt == NULL) return;            // Nothing to visit
  if (rt->isLeaf()) {                 // Do leaf node
    cout << "Leaf: " << ((LeafNode *)rt)->value() << "\n";
    traverse(((LeafNode *)rt)->rightchild());
  }
  else {                             // Do internal node
    cout << "Internal: " << ((IntlNode *)rt)->value() << "\n";
    traverse(((IntlNode *)rt)->leftchild());
    traverse(((IntlNode *)rt)->rightchild());
  }
}

// 查找双链树中结点,rt为根,val为要找的关键码,返回值为空则查找失败,
// 否则为属性值。
// 查找普通的关键码,关键码并不需要以“*”结尾
Attr doubletree_search(CharTreeNode* rt, char* val) {
    int i = 0, len;    CharTreeNode *p;
    p = rt;   len = strlen(val);
    while (p != NULL && i < len)  {
        while (p != NULL && p->symbol < val[i]) // 查找关键码的第i位
            p = ((IntlNode *)p)->rightchild( );
        if (p == NULL || p->symbol > val[i])
            return NULL;
     //   if (i < len - 1)   // p->symbol == val[i]
        p = ((IntlNode *)p)->leftchild( );
        i++;     // 继续查找下一位
    }
    if (p == NULL)
        return NULL;
    else if (p->isLeaf())
            return(((LeafNode *)p)->value());   // 存在此关键码
         else return NULL;   // 虽然查到最后一位,但没有此关键码,即没有“*”
}

// 插入值为'*'的结点到字符树中结点p之前,其中rt为根,q为p的前驱,
// attribute为要插入的属性。
Attr insertLeaf(CharTreeNode* &rt, CharTreeNode *q, CharTreeNode *p,
                Attr attribute) {
    CharTreeNode *s;
    Attr tempattr;

    tempattr = new char [strlen(attribute)];
    strcpy(tempattr, attribute);
    s = new LeafNode(tempattr, p);
    if (q == NULL)
       rt = s;
    else if (((IntlNode *)q)->leftchild() == p)
             ((IntlNode *)q)->setleft(s);
         else ((IntlNode *)q)->setright(s);
    return ((LeafNode *)s)->value( );
}

// 插入val从i开始的子串到字符树中结点p之前,其中rt为根,q为p的前驱,
// attribute为要插入的属性。
Attr insertSubtree(CharTreeNode* &rt, CharTreeNode *q, CharTreeNode *p, char *val, 
                int i, Attr attribute) {
    CharTreeNode *s;
    int len;
    len = strlen(val);
    s = new IntlNode(val[i], NULL, p);
    if (q == NULL) rt = s;
    else {
        if (((IntlNode *)q)->leftchild() == p)
	       ((IntlNode *)q)->setleft(s);
        else ((IntlNode *)q)->setright(s);
//        ((IntlNode *)s)->setright(p);
    }
    for (int j=i+1; j<len; j++)  {
       p = new IntlNode(val[j], NULL, NULL);
       ((IntlNode *)s)->setleft(p);
       s = ((IntlNode *)s)->leftchild();
    }
    return insertLeaf(rt, s, NULL, attribute); 
}

// 插入双链树中结点,rt为根,val为要插入的关键码,
// 返回值为属性值(地址)。字符树是有序的。
// 插入普通的关键码,关键码并不需要以“*”结尾
Attr doubletree_insert(CharTreeNode* &rt, char* val, Attr attribute) {
    int i = 0, len;   CharTreeNode *p, *q;
    p = rt;  q = NULL;
    len = strlen(val);
    if (rt == NULL) return insertSubtree(rt, q, p, val, i, attribute);
    while (p != NULL && i < len)  {
        while (p != NULL && p->symbol < val[i]) { // 查找关键码的第i位
            q = p;
            p = ((IntlNode *)p)->rightchild( );
        }
        if (p != NULL && p->symbol == val[i])  {            
            q = p;   p = ((IntlNode *)p)->leftchild( );
            if (i < len-1)    i++;     // 继续查找下一位
            else {
                if (p->isLeaf())
                    return ((LeafNode *)p)->value();  // 不需要插入
                else  return insertLeaf(rt, q, p, attribute); 
            }
        }   // of if (p != NULL && p->symbol == val[i])
        else return insertSubtree(rt, q, p, val, i, attribute);
    }  // of while (p != NULL && i < len)
    return NULL;
}

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

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

⌨️ 快捷键说明

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