C语言之二叉树(一)

一、树的定义

树是由n(n >= 0)个节点组成的有限集合。如果n = 0,则称之为空树。

如下图所示

1.A为根节点,它只有直接后驱,但是没有直接前驱。

2.除根以外的其他节点划分为m(m >= 0)个互不相交的有限集合T0,T1..........,TN,每个集合又是一棵树,并称之为根的子树。每棵子树的节点仅有一个直接前驱,但可以有0个或者多个直接后继。途中B和C就是A的子树,他们的直接前驱都只有一个,但是后继则不确定。

下面介绍一些树的基础概念:

1.节点:表示树中的元素,概括数据元素的内容及其指向其子树的分支。上图中所有蓝色圆点都是节点。

2.节点的度:节点的分支数。例如A的度为2,H的度为0。

3.终端节点:分支数为0的节点。上图最下层节点都为终端节点。

4.非终端节点:分支数不为0的节点。

5.节点的层次:树中根节点的层次为1,根节点子树为第2层,依此类推。上图A的层次为1,B的层次为2,D的层次为3,

H的层次为5。

6.树的度:树中所有节点度的最大值。

7.树的深度:树中所有节点层次的最大值。需要注意的是,树的深度是从上往下数,树的高度是从下往上数。

8.有序树、无序树:如果树中每棵子树从左向右的排列拥有一定的顺序不得互换,则称之为有序树,否则称之为无序树。

9.森林:是m(m >= 0)棵互不相交的树的集合。

在树的结构中,节点之间的关系还可以用家族关系来描述:

1.孩子、双亲:某个节点的子树称之为这个节点的孩子,而这个节点又被称之为孩子的双亲。

2.子孙:以某节点为根的子树中所有节点都被称为该节点的子孙。

3.祖先:从根节点到该节点路径上的节点都称之为该节点的祖先。

4.兄弟:同一个双亲的孩子相互为兄弟。

5.堂兄弟:双亲在同一层的节点互为堂兄弟。

 

二、二叉树的定义

二叉树是一种有序树,它是节点的一个有限集合,该集合或者为空,或者是由一个根节点加上两棵分别称之为左子树和右子树的互不相交的二叉树组成。他的特点是每个节点至多有两棵子树(即二叉树里面不存在度大于2的节点),并且,二叉树的子树有左右之分,其次序不能任意颠倒。二叉树有以下5种形态:

在实际使用过程中,有两种常见的特殊形态的二叉树。

1.满二叉树

一棵深度为K且有2^{_{k}}-1个节点的二叉树称之为满二叉树。

2.完全二叉树

若设二叉树的高度为h,则共有h层。除第h层外,其他各层的节点数都达到最大个数,第h层从右向左连续若干节点,这就是完全二叉树。

                                完全二叉树                                                              非完全二叉树

 

三、代码构建二叉树

下面代码创建一个顺序二叉树。二叉树每个节点都是一个char型的数据,并且这个二叉树遵循以下规则:

1.所有右孩子的数值大于根节点。

2.所有左孩子的数值小于根节点。

为了程序简易处理,先设定一个数据集合及构建顺序(数据的构建顺序自左向右):e、f、g、h、a、c、b、d。

对应二叉树如下图所示:

 下例代码并没有对二叉树进行遍历,遍历部分内容下个章节进行介绍。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>


typedef struct LINK_T                                //二叉树节点结构体
{
  int data;
  struct LINK_T *lchild;
  struct LINK_T *rchild;
}_LINK_T;


_LINK_T *Create_Node(int data);                      //创建二叉树结构点         
_LINK_T *Construct(_LINK_T *head, _LINK_T *node);    //构造二叉树
_LINK_T *Traverse_P(_LINK_T *head);                  //遍历二叉树
int main(int argc, const char *argv[])
{
  int i = 0;
  int data[8] = {'e', 'f', 'h', 'g', 'a', 'c', 'b', 'd'};
  _LINK_T *head;
  head = (_LINK_T*)malloc(sizeof(_LINK_T));
  memset(head, 0, sizeof(head));
  head->data = 0;
  head->lchild = NULL;
  head->rchild = NULL;

  for (i = 0; i < 8; i++)
  {
    Construct(head, Create_Node(data[i]));		
  
  }

  return 0;
}

_LINK_T *Create_Node(int data)
{
  _LINK_T *node;
  node = (_LINK_T*)malloc(sizeof(_LINK_T)); 
  memset(node, 0, sizeof(node));
  node->data = data;
  node->lchild = NULL;
  node->rchild = NULL;

  return node;
}

_LINK_T *Construct(_LINK_T *head, _LINK_T *node)
{
  int i = 0;
  _LINK_T *temp = head;

  while(1)
  {
 
    if (temp->data == 0)                   //第一次插入根节点
    {
      temp->data = node->data;
      break;
    }
    else if (node->data < temp->data)      //如果插入数值小于节点数值,则插入到节点左侧
    {
      if (!temp->lchild)                   //如果左孩子为空,则数据保存到左孩子上         
      {
        temp->lchild = node;
        break;
      }
      else                                 //左孩不为空,则将指针移向左孩
      {
        temp = temp->lchild;
        continue;
      }
    }
    else if (node->data > temp->data)     //如果插入数值大于节点数值,则插入到节点右侧
    {
      if (!temp->rchild)                  //如果右孩子为空,则数据保存到右孩子上         
      {
        temp->rchild = node;
        break;
      }
      else                                //右孩不为空,则将指针移向右孩
      {
        temp = temp->rchild;
        continue;
      }
    }
  
  }

  return;
}

 

仓促成文,不当之处,尚祈方家和读者批评指正。联系邮箱[email protected]

 

 

 

发布了12 篇原创文章 · 获赞 5 · 访问量 639

猜你喜欢

转载自blog.csdn.net/qq_35600620/article/details/104017330