前面我们谈到了排序二叉树,还没有熟悉的同学可以看一下这个,二叉树基本操作二叉树插入二叉树删除1删除2删除3。但是排序二叉树也不是没有缺点,比如说,如果我们想在排序二叉树中删除一段数据的节点怎么办呢?按照现在的结构,我们只能一个一个数据查找验证,首先看看在不在排序二叉树中,如果在那么删除;如果没有这个数据,那么继续查找。那么有没有方法,可以保存当前节点的下一个节点是什么呢?这样就不再需要进行无谓的查找了。其实这样的方法是存在的,那就是在排序二叉树中添加向前向后双向节点。
    现在数据结构定义如下:

typedef struct _TREE_NODE
{
int data;
struct _TREE_NODE* prev;
struct _TREE_NODE* next;
struct _TREE_NODE* left;
struct _TREE_NODE* right;
}TREE_NODE;

拿节点的添加来说,我们可能需要添加prev、next的处理步骤。

void set_link_for_insert(TREE_NODE* pParent, TREE_NODE* pNode)
{
if(NULL == pParent || NULL == pNode)
return; if(pNode = pParent->left){
pNode->prev = pParent->prev;
if(pParent->prev)
pParent->prev->next = pNode;
pNode->next = pParent;
pParent->prev = pNode;
}else{
pNode->next = pParent->next;
if(pParent->next)
pParent->next->prev = pNode;
pNode->prev = pParent;
pParent->next = pNode;
} return;
} STATUS add_node_into_tree(TREE_NODE** ppTreeNode, int data)
{
TREE_NODE* pHead;
TREE_NODE* pNode; if(NULL == ppTreeNode)
return FALSE; if(NULL == *ppTreeNode){
*ppTreeNode = create_new_node(data);
return TRUE;
} if(NULL != find_data_in_tree(*ppTreeNode, data))
return FALSE; pHead = *ppTreeNode;
while(1){
if(data < pHead->data){
if(pHead->left){
pHead = pHead->left;
}else{
pNode = create_new_node(data);
pHead->left = pNode;
break;
}
}else{
if(pHead->right){
pHead = pHead->right;
}else{
pNode = create_new_node(data);
pHead->right = pNode;
break;
}
}
} set_link_for_insert(pHead, pNode);
return TRUE;
}

添加节点如此,删除节点的工作也不能马虎。

void set_link_for_delete(TREE_NODE* pNode)
{
if(pNode->prev){
if(pNode->next){
pNode->prev->next = pNode->next;
pNode->next->prev = pNode->prev;
}else
pNode->prev->next = NULL;
}else{
if(pNode->next)
pNode->next->prev = NULL;
}
} TREE_NODE* _delete_node_from_tree(TREE_NODE* root, TREE_NODE* pNode)
{
TREE_NODE* pLeftMax;
TREE_NODE* pLeftMaxParent;
TREE_NODE* pParent = get_parent_of_one(root, pNode); if(NULL == pNode->left && NULL == pNode->right){
if(pNode == pParent->left)
pParent->left = NULL;
else
pParent->right = NULL;
}else if(NULL != pNode->left && NULL == pNode->right){
if (pNode == pParent->left)
pParent->left = pNode->left;
else
pParent->right = pNode->left;
}else if(NULL == pNode->left && NULL != pNode->right){
if(pNode == pParent->left)
pParent->left = pNode->right;
else
pParent->right = pNode->right;
}else{
pLeftMax = get_max_node_of_one(pNode->left);
if(pLeftMax == pNode->left){
pNode->left->right = pNode->right;
if(pNode == pParent->left)
pParent->left = pNode->left;
else
pParent->right = pNode->left;
}else{
pLeftMaxParent = get_parent_of_one(root, pLeftMax);
pNode->data = pLeftMax->data;
pLeftMaxParent->right = NULL;
pNode = pLeftMax;
}
} return pNode;
} STATUS delete_node_from_tree(TREE_NODE** ppTreeNode, int data)
{
TREE_NODE* pNode;
TREE_NODE* pLeftMax;
TREE_NODE* pLeftMaxParent; if(NULL == ppTreeNode || NULL == *ppTreeNode)
return FALSE; if(NULL == (pNode = find_data_in_tree(*ppTreeNode, data)))
return FALSE; if(pNode == *ppTreeNode){
if(NULL == pNode->left && NULL == pNode->right)
*ppTreeNode = NULL;
else if(NULL != pNode->left && NULL == pNode->right)
*ppTreeNode = pNode->left;
else if(NULL == pNode->left && NULL != pNode->right)
*ppTreeNode = pNode->right;
else {
pLeftMax = get_max_node_of_one(pNode->left);
if(pNode->left == pLeftMax){
pNode->left->right = pNode->right;
*ppTreeNode = pNode->left;
}else{
pLeftMaxParent = get_parent_of_one(*ppTreeNode, pLeftMax);
pNode->data = pLeftMax->data;
pLeftMaxParent->right = NULL;
pNode = pLeftMax;
}
} goto final;
} pNode = _delete_node_from_tree(*ppTreeNode, pNode); final:
set_link_for_delete(pNode); free(pNode);
return TRUE;
}

其中,寻找最大值节点和寻找父节点的代码如下所示:

TREE_NODE* get_max_node_of_one(TREE_NODE* pNode)
{
if(NULL == pNode)
return NULL; while(pNode->right)
pNode = pNode->right; return pNode;
} TREE_NODE* get_parent_of_one(TREE_NODE* root, TREE_NODE* pNode)
{
if(NULL == root || NULL == pNode)
return NULL; while(root){
if(pNode == root->left || pNode == root->right)
return root;
else if(pNode->data < root->data)
root = root->left;
else
root = root->right;
} return NULL;
}

总结:
    (1)排序二叉树的序列化关键就是在二叉树节点添加前向指针和后继指针
    (2)排序二叉树是空间换时间的典型案例
    (3)排序二叉树是很多结构的基础,写多少遍都不为多,有机会朋友们应该多加练习
    (4)测试用例的编写是代码编写的关键,编写程序的目的就是为了消除bug,特别是低级bug

c++(排序二叉树线索化)的更多相关文章

  1. 数据结构之二叉树篇卷四 -- 二叉树线索化(With Java)

    一.线索二叉树简介 二叉树本身是一种非线性结构,然而当你对二叉树进行遍历时,你会发现遍历结果是一个线性序列.这个序列中的节点存在前驱后继关系.因此,如何将这种前驱后继信息赋予给原本的二叉树呢?这就是二 ...

  2. 记忆化搜索 codevs 2241 排序二叉树

    codevs 2241 排序二叉树 ★   输入文件:bstree.in   输出文件:bstree.out   简单对比时间限制:1 s   内存限制:128 MB [问题描述] 一个边长为n的正三 ...

  3. 算法与数据结构(三) 二叉树的遍历及其线索化(Swift版)

    前面两篇博客介绍了线性表的顺序存储与链式存储以及对应的操作,并且还聊了栈与队列的相关内容.本篇博客我们就继续聊数据结构的相关东西,并且所涉及的相关Demo依然使用面向对象语言Swift来表示.本篇博客 ...

  4. 遍历二叉树 traversing binary tree 线索二叉树 threaded binary tree 线索链表 线索化

    遍历二叉树   traversing binary tree 线索二叉树 threaded binary tree 线索链表 线索化 1. 二叉树3个基本单元组成:根节点.左子树.右子树 以L.D.R ...

  5. 树和二叉树->线索二叉树

    文字描述 从二叉树的遍历可知,遍历二叉树的输出结果可看成一个线性队列,使得每个结点(除第一个和最后一个外)在这个线形队列中有且仅有一个前驱和一个后继.但是当采用二叉链表作为二叉树的存储结构时,只能得到 ...

  6. C++11 智能指针unique_ptr使用 -- 以排序二叉树为例

    用智能指针可以简化内存管理.以树为例,如果用普通指针,通常是在插入新节点时用new,在析构函数中调用delete:但有了unique_ptr类型的智能指针,就不需要在析构函数中delete了,因为当u ...

  7. 数据结构与算法系列研究五——树、二叉树、三叉树、平衡排序二叉树AVL

    树.二叉树.三叉树.平衡排序二叉树AVL 一.树的定义 树是计算机算法最重要的非线性结构.树中每个数据元素至多有一个直接前驱,但可以有多个直接后继.树是一种以分支关系定义的层次结构.    a.树是n ...

  8. c++(排序二叉树删除)

    相比较节点的添加,平衡二叉树的删除要复杂一些.因为在删除的过程中,你要考虑到不同的情况,针对每一种不同的情况,你要有针对性的反应和调整.所以在代码编写的过程中,我们可以一边写代码,一边写测试用例.编写 ...

  9. c++(排序二叉树)

    前面我们讲过双向链表的数据结构.每一个循环节点有两个指针,一个指向前面一个节点,一个指向后继节点,这样所有的节点像一颗颗珍珠一样被一根线穿在了一起.然而今天我们讨论的数据结构却有一点不同,它有三个节点 ...

随机推荐

  1. Python 多线程进程高级指南(二)

    本文是如何<优雅地实现Python通用多线程/进程并行模块>的后续.因为我发现,自认为懂了一点多线程开发的皮毛,写了那么个multi_helper的玩意儿,后来才发现我靠原来就是一坨屎.自 ...

  2. lesson - 1 笔记 网络连接 /putty 密钥登陆

    ---笔记 一.网络连接配置 1. 查看电脑ip 地址: ifconfig -a  2. 自动获取ip 地址: dhclient   默认BOOTPROTO=dhcp  和真机同一网段 3. 手动配置 ...

  3. 10 Easy Steps to a Complete Understanding of SQL

    原文出处:http://tech.pro/tutorial/1555/10-easy-steps-to-a-complete-understanding-of-sql(已经失效,现在收集如下) Too ...

  4. Mysql 索引优化分析

    MySQL索引优化分析 为什么你写的sql查询慢?为什么你建的索引常失效?通过本章内容,你将学会MySQL性能下降的原因,索引的简介,索引创建的原则,explain命令的使用,以及explain输出字 ...

  5. Javascript流程控制

    Javascript流程控制 1.条件语句 (1)if(exp)执行一句代码 (2)if(exp){执行代码段;} (3)if(exp){exp为true执行代码段}else{exp为false执行的 ...

  6. 一些JavaScript技巧

    1.获取浏览器的高度和宽度(不包括工具栏和滚动条): var w=window.innerWidth //现代浏览器 || document.documentElement.clientWidth / ...

  7. Travis CI实现持续部署

    安装Ruby 2.0以上版本并安装travis的命令行工具 可以看出我的已经是安装好的(Ubuntu 16.04.3 LTS 系统) ruby -v ruby --) [x86_64-linux-gn ...

  8. HTML、CSS、JS 复习——序

    HTML在MVC中担任着M的角色.由HTML组成的节点称之为HTML DOM.要想成为一流的大神,就必须能分分钟建立起一个强大的HTML DOM.而要做到这点,就必须了解甚至精通HTML. CSS在M ...

  9. 最新版solr7.2集群搭建详细步骤

    集群:高可用,备份,数据可分片 需要运行4个tomcat 1.tomcat端口号(默认占用8005,8009,8080三个端口) tomcat服务 占用端口 tomcat1 6005.6060.600 ...

  10. UWP 手绘视频创作工具技术分享系列 - 全新的 UWP 来画视频

    从2017年11月开始,我们开始规划和开发全新的来画Pro,在12月23日的短视频峰会上推出了预览版供参会者体验,得到了很高的评价和关注度.吸取反馈建议后,终于在2018年1月11日正式推出了全新版本 ...