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

来源:互联网 发布:金牛网络 编辑:程序博客网 时间:2024/05/11 19:37


在上一节中,我们为树结点添加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)改写和添加新的操作产生很大影响。因此,在扩张数据结构时可以采用
试错法,尝试添加不同的域,权衡各种方案的优劣。


原创粉丝点击