服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - C语言 数据结构之中序二叉树实例详解

C语言 数据结构之中序二叉树实例详解

2021-04-28 12:19dread_naught C/C++

这篇文章主要介绍了C语言 数据结构之中序二叉树实例详解的相关资料,需要的朋友可以参考下

C语言数据结构 中序二叉树

前言:

线索二叉树主要是为了解决查找结点的线性前驱与后继不方便的难题。它只增加了两个标志性域,就可以充分利用没有左或右孩子的结点的左右孩子的存储空间来存放该结点的线性前驱结点与线性后继结点。两个标志性域所占用的空间是极少的,所有充分利用了二叉链表中空闲存的储空间。

   要实现线索二叉树,就必须定义二叉链表结点数据结构如下(定义请看代码):

 

 

left

leftTag

data

rightTag

right

 

说明:

1.       leftTag=false时,表示left指向该结点的左孩子;

2.       leftTag=true时,表示left指向该结点的线性前驱结点;

3.       rightTag=false时,表示right指向该结点的右孩子;

4.       rightTag=true时,表示right指向该结点的线性后继结点;

     以二叉链表结点数据结构所构成的二叉链表作为二叉树的存储结构,叫做线索二叉链表;指向结点的线性前驱或者线性后继结点的指针叫做线索;加上线索的二叉树称为线索二叉树;对二叉树以某种次序遍历将其变为线索二叉树的过程叫做线索化。

中序次序线索化二叉树算法:

  中序次序线索化是指用二叉链表结点数据结构建立二叉树的二叉链表,然后按照中序遍历的方法访问结点时建立线索;(具体看代码)

检索中序二叉树某结点的线性前驱结点的算法:

1.       如果该结点的leftTag=true,那么left就是它的线性前驱;

2.       如果该结点的leftTag=false,那么该结点左子树最右边的尾结点就是它的线性前驱点;

(具体请看代码)

检索中序二叉树某结点的线性后继结点和算法:

1.       如果该结点的right=true,那么right就是它的线性后继结点;

2.       如果该结点的right=false,那么该结点右子树最左边的尾结点就是它的线性后继结点

(具体请看代码)

C语言 数据结构之中序二叉树实例详解

图:后继线索

C语言 数据结构之中序二叉树实例详解

图:前驱线索

 节点定义:

?
1
2
3
4
5
6
7
8
9
struct Node
{
  int data;
  bool leftTag;
  bool rightTag;
  Node* left;
  Node* right;
  Node(int _data):data(_data),left(0),right(0),leftTag(false),rightTag(false){}
};

类定义:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class BinaryTree
{
private:
  Node* root;
private:
  Node* head;
  Node* pre;
  void makeThread(Node* node);
public:
  void buildThread();
  void traverseBySuccessor();
  void traverseByPredecessor();
 
// helper methods
private:
  static inline bool visit(Node* T)
  {
    if (T)
    {
      printf("data:%c, left:%c, right:%c\n",
        (char)T->data,
        (T->left!=0) ? (char)T->left->data : '#',
        (T->right!=0) ? (char)T->right->data : '#');
      return true;
    }
    else return false;
  }
};

方法定义:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
void BinaryTree::makeThread(Node* node)
{
  if (node!=NULL)
  {
    makeThread(node->left);
    if (pre!= NULL)
    {
      if (pre->right==NULL) // 如果前驱节点的右子树为空, 那么把前驱节点的右子树用作线索
      {
        pre->rightTag = true
        pre->right = node;
      }
      else pre->rightTag = false;
    }
    if (node->left==NULL) // 如果当前结点的左子树为空, 那么把当前结点的左子树用作线索
    {
      node->leftTag = true;
      node->left = pre;
    }
    else node->leftTag = false;
    pre = node;
    makeThread(node->right);
  }
}
 
void BinaryTree::traverseBySuccessor()
{
  Node* p = head->left; //first find the root node
  // 亲测表明 如果不使用head哑节点 就要设三道卡, 防止p访问到NULL, 
  // 分别在主while处, 第二个visit处和下面的p=p->right处
  while (p!=head)
  {
    while (!p->leftTag)
      p = p->left;
    visit(p);
 
    while (p->rightTag && p->right!=head)
    {
      p = p->right;
      visit(p);
    }
    p = p->right;
  }
  cout<<endl;
}
 
void BinaryTree::traverseByPredecessor()
{
  Node* p = head->left; //first find the root node
  while (p!=head)
  {
    while (!p->rightTag)
      p = p->right;
    visit(p);
    if (p!=NULL)
    {
      while (p->leftTag && p->left!=head)
      {
        p = p->left;
        visit(p);
      }
      p = p->left;
    }
  }
  cout<<endl;
}
 
void BinaryTree::buildThread()
{
  pre = NULL;
  head = new Node('@');
  head->left = root;
  head->right = head;
  makeThread(root);
  // 经过了makeThread过程之后, pre必然指向中序遍历最晚的结点.
  // 把pre的右子树指向head, 就构成了一个双向循环链表
  //
  pre->rightTag = 1;
  pre->right = head;
  pre = NULL;
  Node* p = root;
  /*
   * 在建立前驱线索的时候,最左边的结点没有和head结点连接。要在这里补上
   */
  while (p->left!=NULL)
    p = p->left;
  p->left = head;
}

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

原文链接:http://blog.csdn.net/dread_naught/article/details/41786041

延伸 · 阅读

精彩推荐
  • C/C++OpenCV实现拼接图像的简单方法

    OpenCV实现拼接图像的简单方法

    这篇文章主要为大家详细介绍了OpenCV实现拼接图像的简单方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    iteye_183805102021-07-29
  • C/C++c/c++实现获取域名的IP地址

    c/c++实现获取域名的IP地址

    本文给大家汇总介绍了使用c/c++实现获取域名的IP地址的几种方法以及这些方法的核心函数gethostbyname的详细用法,非常的实用,有需要的小伙伴可以参考下...

    C++教程网10262021-03-16
  • C/C++C语言main函数的三种形式实例详解

    C语言main函数的三种形式实例详解

    这篇文章主要介绍了 C语言main函数的三种形式实例详解的相关资料,需要的朋友可以参考下...

    ieearth6912021-05-16
  • C/C++深入C++拷贝构造函数的总结详解

    深入C++拷贝构造函数的总结详解

    本篇文章是对C++中拷贝构造函数进行了总结与介绍。需要的朋友参考下...

    C++教程网5182020-11-30
  • C/C++c/c++内存分配大小实例讲解

    c/c++内存分配大小实例讲解

    在本篇文章里小编给大家整理了一篇关于c/c++内存分配大小实例讲解内容,有需要的朋友们可以跟着学习参考下。...

    jihite5172022-02-22
  • C/C++使用C++制作简单的web服务器(续)

    使用C++制作简单的web服务器(续)

    本文承接上文《使用C++制作简单的web服务器》,把web服务器做的功能稍微强大些,主要增加的功能是从文件中读取网页并返回给客户端,而不是把网页代码...

    C++教程网5492021-02-22
  • C/C++C语言实现双人五子棋游戏

    C语言实现双人五子棋游戏

    这篇文章主要为大家详细介绍了C语言实现双人五子棋游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    两片空白7312021-11-12
  • C/C++关于C语言中E-R图的详解

    关于C语言中E-R图的详解

    今天小编就为大家分享一篇关于关于C语言中E-R图的详解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看...

    Struggler095962021-07-12