• 《算法导论》第14章 数据结构的扩张 (2)



    在上一节中,我们为树结点添加size域表示每颗子树的大小,即包含的结点个数,扩张了
    二叉查找树为其增加顺序统计量的查找功能。更为自然的想法是直接添加顺序统计量rank域
    到每个树结点上。这一节我们就来看下在这样的设计下,如何扩张来完成上一节相同的功能。

    当我们插入一个结点到二叉树中,假设它的顺序统计量为5,那么之前二叉树中顺序统计量
    大于5的结点都要更新。也就是说插入一个新结点到对应的位置后,要不断地查找其后继,
    完成rank域的更新。所以可以结合习题14.2-1,再添加两个指针域prev和next指向前趋和后继,
    使查找前趋和后继在O(1)内完成。

    下面来看具体代码。

    // 添加三个新域
    typedef struct _BSTNode {
         struct _BSTNode *left, *right, *parent;
         int key;
         char *value;
         struct _BSTNode *prev, *next;
         int rank;
    } BSTNode;
    
    // 对于prev和next指针的维护,插入结点分两种情况:
    // 1.新插入结点newNode是其父结点P的左子结点,说明P->prev < newNode < P
    // 2.新插入结点newNode是其父结点P的右子结点,说明P < newNode < P->next
    //
    // 对于rank域,如果newNode没有前趋,那么rank置为1,否则置为newNode前趋的rank值加1
    // 之后开始迭代更新,将newNode的所有后继的rank值都加1。
    void bst_insert(BSTNode **root, BSTNode *newNode)
    {
         // Locate insert location
         BSTNode *pNode = NULL;
         BSTNode *node = *root;
         while (node != NULL) {
              pNode = node;
              if (newNode->key < node->key)
                   node = node->left;
              else
                   node = node->right;
         }
         
         // Link newNode to pNode
         newNode->parent = pNode;
    
         // Link pNode to newNode
         // 新逻辑:维护prev, next
         if (pNode == NULL) {
              *root = newNode;
         } else if (newNode->key < pNode->key) {
              pNode->left = newNode;
    
              // newNode is between pNode->prev and pNode
              if (pNode->prev != NULL)
                   pNode->prev->next = newNode;
              newNode->prev = pNode->prev;
              pNode->prev = newNode;          
              newNode->next = pNode;
         } 
         else {
              pNode->right = newNode;          
    
              // newNode is between pNode and pNode->next          
              if (pNode->next != NULL)
                   pNode->next->prev = newNode;
              newNode->next = pNode->next;
              newNode->prev = pNode;
              pNode->next = newNode;
         }
    
         // 新逻辑:维护rank域
         if (newNode->prev == NULL)
              newNode->rank = 1;
         else
              newNode->rank = newNode->prev->rank + 1;
         
         BSTNode *succesor = newNode;
         while ((succesor = succesor->next) != NULL) {
              succesor->rank += 1;
         }
    }
    
    // Select和Rank操作变得格外简单
    BSTNode *bst_os_select(BSTNode *node, int i)
    {
         while (node != NULL) {
              if (node->rank == i)
                   return node;
              else if (node->rank > i)
                   node = node->left;
              else
                   node = node->right;
         }
         return NULL;
    }
    
    int bst_os_rank(BSTNode *node)
    {
         return node->rank;
    }

    通过这一节和上一节的对比,可以看出在步骤(2)中对基础数据结构添加不同的域,会对
    步骤(3)和(4)改写和添加新的操作产生很大影响。因此,在扩张数据结构时可以采用
    试错法,尝试添加不同的域,权衡各种方案的优劣。


  • 相关阅读:
    HDFS 常用命令
    CentOS6.5和RedHat6.5下以rpm方式安装mysql-5.6.20
    RedHat安装yum+配置国内yum源
    nginx 一般配置实例 静态页面
    PHP计划任务之关闭浏览器后仍然继续执行的函数 ignore_user_abort
    php函数——『解析 xml数据』
    基于php-fpm的配置详解[转载]
    解决nginx: [error] open() "/usr/local/nginx/logs/nginx.pid" failed错误
    nginx的优化
    Nginx fastcgi_param解释
  • 原文地址:https://www.cnblogs.com/xiaomaohai/p/6157847.html
Copyright © 2020-2023  润新知