树(Tree)是 n(n≥0)个相同类型的数据元素的有限集合。树中的数据元素叫结点(Node)。n=0 的树称为空树(Empty Tree);对于 n>0 的任意非空树 T 有: (1)有且仅有一个特殊的结点称为树的根(Root)结点,根没有前驱结点; (2)若n>1,则除根结点外,其余结点被分成了m(m>0)个互不相交的集合T1,T2,…,Tm,其中每一个集合Ti(1≤i≤m)本身又是一棵树。树T1,T2,…,Tm称为这棵树的子树(Subtree)

二叉树(Binary Tree)是 n(n≥0)个相同类型的结点的有限集合。n=0 的二叉树称为空二叉树(Empty Binary Tree);对于 n>0 的任意非空二叉树有:
(1)有且仅有一个特殊的结点称为二叉树的根(Root)结点,根没有前驱结点;
(2)若n>1,则除根结点外,其余结点被分成了 2 个互不相交的集合TL,TR,而TL、TR本身又是一棵二叉树,分别称为这棵二叉树的左子树(Left Subtree)和右子树(Right Subtree)。

1)满二叉树(Full Binary Tree):如果一棵二叉树只有度为 0 的结点和度为 2的结点,并且度为 0 的结点在同一层上,则这棵二叉树为满二叉树

(2)完全二叉树(Complete Binary Tree):深度为 k,有 n 个结点的二叉树当且仅当其每一个结点都与深度为 k,有 n 个结点的满二叉树中编号从1到n的结点一一对应时,称为完全二叉树

二叉树的存储结构主要有三种:顺序存储结构、二叉链表存储结构和三叉链表存储结构

二叉链表存储结构的类实现
二叉树的二叉链表的结点类有3个成员字段:数据域字段data、左孩子引用域字段lChild和右孩子引用域字段rChild。

 public class Node<T>
{
private T data;//数据域 public T Data
{
get { return data; }
set { data = value; }
}
private Node<T> lchild;//左孩子 public Node<T> Lchild
{
get { return lchild; }
set { lchild = value; }
}
private Node<T> rchild;//右孩子 public Node<T> Rchild
{
get { return rchild; }
set { rchild = value; }
}
public Node()
{
data = default(T);
lchild = null;
rchild = null;
}
public Node(T data )
{
this.data = data;
lchild = null;
rchild = null;
} public Node(T data, Node<T> lchild, Node<T> rchlid)
{
this.data = data;
this.lchild = lchild;
this.rchild = rchild;
}
}

不带头结点的二叉树的二叉链表比带头结点的二叉树的二叉链表的区别与不带头结点的单链表与带头结点的单链表的区别一样。

下面只介绍不带头结点的二叉树的二叉链表的类

public class BinaryTree<T>
{
private Node<T> head; //头引用 internal Node<T> Head
{
get { return head; }
set { head = value; }
} public BinaryTree()
{
head = null;
}
public BinaryTree(T data)
{
Node<T> p = new Node<T>(data);
head = p;
}
public BinaryTree(T data, Node<T> lchild, Node<T> rchild)
{
Node<T> p = new Node<T>(data, lchild, rchild);
head = p;
}
// 二叉树是否为空
public bool IsEmptyTree()
{
if (null != head)
{
return false;
}
else
{
return true;
}
} // 获取根节点
public Node<T> GetRoot()
{
if (IsEmptyTree())
{
return null;
}
return head;
}
//获取结点的左孩子结点
public Node<T> GetLChild(Node<T> p)
{
return p.Lchild;
}
// right child
public Node<T> GetRChild(Node<T> p)
{
return p.Rchild;
}
//将结点p的左子树插入值为val的新结点,
//原来的左子树成为新结点的左子树
public void InsertL(T val, Node<T> p)
{
Node<T> temp = new Node<T>(val);
temp.Lchild = p.Lchild;
p.Lchild = temp;
} //将结点p的右子树插入值为val的新结点,
//原来的右子树成为新结点的右子树
public void InsertR(T val, Node<T> p)
{
Node<T> tmp = new Node<T>(val);
tmp.Rchild = p.Rchild;
p.Rchild = tmp;
}
//若p非空,删除p的左子树
public Node<T> DeleteL(Node<T> p)
{
if (p == null || p.Lchild == null)
{
return null;
}
Node<T> temp = p.Lchild;
p.Lchild = null;
return temp;
} //若p非空,删除p的右子树
public Node<T> DeleteR(Node<T> p)
{
if (p == null || p.Rchild == null)
{
return null;
}
Node<T> temp = p.Rchild;
p.Rchild = null;
return temp;
}
//判断是否是叶子结点
public bool IsLeaf(Node<T> p)
{
if ( p != null && p.Lchild == null && p.Rchild == null)
{
return true;
}
return false;
}
// 销毁二叉树
public void DestroyTree( Node<T> node )
{
if ( node != null )
{
if (node.Lchild != null)
{
node.Lchild = null;
}
if (node.Rchild != null)
{
node.Rchild = null;
}
node = null;
}
} // 1、先序遍历(DLR)
public void PreOredr(Node<T> root)
{
if ( root == null )
{
//Console.WriteLine("树为空,无法遍历");
return;
}
//处理根结点
Console.WriteLine("{0}", root.Data);
//先序遍历左子树
PreOredr(root.Lchild);
//再遍历右子树
PreOredr(root.Rchild);
} /*
2、中序遍历(LDR)
中序遍历的基本思想是:首先中序遍历根结点的左子树,然后访问根结点,
最后中序遍历其右子树
*/
public void InOrder(Node<T> root)
{
if (root.Lchild != null)
{
InOrder(root.Lchild);
} Console.WriteLine( root.Data ); if (root.Rchild != null)
{
InOrder(root.Rchild);
}
}
/*
3、后序遍历(LRD)
后序遍历的基本思想是:首先后序遍历根结点的左子树,然后后序遍历根结
点的右子树,最后访问根结点
*/
public void PostOrder(Node<T> root)
{
if (root.Lchild != null)
{
PostOrder(root.Lchild);
}
if (root.Rchild != null)
{
PostOrder(root.Rchild);
}
Console.WriteLine(root.Data);
} /*
层序遍历的基本思想是:由于层序遍历结点的顺序是先遇到的结点先访问,
与队列操作的顺序相同。所以,在进行层序遍历时,设置一个队列,将根结点引
用入队,当队列非空时,循环执行以下三步:
(1) 从队列中取出一个结点引用,并访问该结点;
(2) 若该结点的左子树非空,将该结点的左子树引用入队;
(3) 若该结点的右子树非空,将该结点的右子树引用入队
*/
public void LevelOrder(Node<T> root)
{
if ( root == null )
{
return;
}
Queue<Node<T>> queue = new Queue<Node<T>>();
queue.Enqueue(root);
while ( queue.Count > )
{
//结点出队
Node<T> temp = queue.Dequeue();
//处理当前结点
Console.WriteLine("结点出队{0}", temp.Data);
//将当前结点的左孩子结点入队
if (temp.Lchild != null)
{
queue.Enqueue(temp.Lchild);
}
if (temp.Rchild != null)
{
queue.Enqueue(temp.Rchild);
}
}
}
}

// 测试

BinaryTree<char> tree = new BinaryTree<char>();
Node<char> p = new Node<char>('A');
Node<char> p1 = new Node<char>('B');
tree.InsertL('B', p);
tree.InsertL('D', p);
tree.InsertR('E', p1);
tree.InsertR('C', p);
tree.InsertR('F', p);
tree.InsertR('G', p);
Console.WriteLine("先序遍历*******************************");
tree.PreOredr(p); //tree.PreOredr(p1);
Console.WriteLine("中序遍历*******************************");
tree.InOrder(p);
Console.WriteLine("后序遍历*******************************");
tree.PostOrder(p);
Console.WriteLine("层序遍历*******************************");
tree.LevelOrder(p);

c#数和二叉树的更多相关文章

  1. [ACM训练] 数据结构----树、二叉树----c++ && python

    树结构,尤其是二叉树结构是算法中常遇见的,这里根据学习过程做一个总结. 二叉树所涉及到的知识点有:满二叉树与完全二叉树.节点数目的关系.节点数与二叉树高度的关系.层次遍历.深度优先遍历.广度优先遍历等 ...

  2. 数据结构——二叉树(Binary Trees)

    非线性数据结构 二叉搜索树(Binary Search Tree) 树的密度=结点数/高度 二叉树类 #pragma once class stnode { public: int nodeValue ...

  3. Android版数据结构与算法(六):树与二叉树

    版权声明:本文出自汪磊的博客,未经作者允许禁止转载. 之前的篇章主要讲解了数据结构中的线性结构,所谓线性结构就是数据与数据之间是一对一的关系,接下来我们就要进入非线性结构的世界了,主要是树与图,好了接 ...

  4. 卡特兰(Catalan)数入门详解

    也许更好的阅读体验 基本概念 介绍 学卡特兰数我觉得可能比组合数要难一点,因为组合数可以很明确的告诉你那个公式是在干什么,而卡特兰数却像是在用大量例子来解释什么时卡特兰数 这里,我对卡特兰数做一点自己 ...

  5. Leetcode823 : 因子二叉树问题

    问题描述 给定一个数组,数组中的数不重复,且均大于1.要求使用数组中的数构建二叉树,每个数字可以被重复使用,除了叶子节点,每个节点的值等于其子节点的乘积,求构建二叉树的数量,返回的结果mod 10** ...

  6. 数据结构(一)二叉树 & avl树 & 红黑树 & B-树 & B+树 & B*树 & R树

    参考文档: avl树:http://lib.csdn.net/article/datastructure/9204 avl树:http://blog.csdn.net/javazejian/artic ...

  7. 二叉树&满二叉树与完全二叉树

    二叉树的定义 二叉树(Binary Tree)是n(n≥0)个元素的有限集合,该集合为空或者为由一个称为"根"的元素及两个不相交的.被分别称为左子树和右子树的二叉树组成 二叉树的基 ...

  8. Java数据结构——树、二叉树的理论知识汇总

    通用树的理论知识 一.树的定义 由一个或多个(n>=0)节点组成的有限集合T,有且仅有一个节点称为根(root),当n>1时,其7余的节点为m(m>=0)个互不相交的有限集合T1,T ...

  9. leetcode_二叉树篇_python

    主要是深度遍历和层序遍历的递归和迭代写法. 另外注意:因为求深度可以从上到下去查 所以需要前序遍历(中左右),而高度只能从下到上去查,所以只能后序遍历(左右中). 所有题目首先考虑root否是空.有的 ...

随机推荐

  1. 解决“Replace wireless configuration ”默认被选上的问题

    方法一 1.打开 /home/tingpan/openwrt/barrier_breaker/feeds/luci/modules/admin-full/luasrc/model/cbi/admin_ ...

  2. C#代码规范和质量检查工具

    代码风格检查:StyleCop The StyleCop tool provides warnings that indicate style and consistency rule violati ...

  3. qt ISO C++ forbids declaration of 'XXXX' with no type

    error: ISO C++ forbids declaration of 'XXXX' with no type   出现这个错误,一般是由于两个CPP相互都相互包含了对方的头文件造成的,比如: 当 ...

  4. 关于lidroid xUtils 开源项目

    最近搜了一些框架供初学者学习,比较了一下XUtils是目前git上比较活跃 功能比较完善的一个框架,是基于afinal开发的,比afinal稳定性提高了不少,下面是介绍: xUtils简介 xUtil ...

  5. Java技术专题之JVM你的内存泄露了吗?

    一.从一个例子开始 关于JVM的内存泄露,让我们从下面一个例子开始吧,大家来判断一下如果按照下面这种分配方式,会不会出现内存泄露呢? import java.util.List; import jav ...

  6. 【FusionCharts学习-3】显示中国地图

    概述 使用FusionCharts显示中国地图 资源获取 地图下载地址:http://www.fusioncharts.com/download/maps/definition/   将下载的地图拷贝 ...

  7. Spring中的后置处理器BeanPostProcessor讲解

    Spring中提供了很多PostProcessor供开发者进行拓展,例如:BeanPostProcessor.BeanFactoryPostProcessor.BeanValidationPostPr ...

  8. springMVC学习(10)-上传图片

    需求:在修改商品页面,添加上传商品图片功能. SpringMVC中对多部件类型解析: 1)springmvc中配置: <!-- 文件上传 --> <bean id="mul ...

  9. springMVC学习(6)-包装pojo类型、数组、list、Map类型参数绑定

    一.包装类型pojo参数绑定: 需求:商品查询controller方法中实现商品查询条件传入. 实现方法: 1)在形参中 添加HttpServletRequest request参数,通过reques ...

  10. Mybatis学习(2)原始dao开发和使用mapper接口代理开发

    基础知识: 1).SqlSessionFactoryBuilder: 通过SqlSessionFactoryBuilder创建会话工厂SqlSessionFactory.将SqlSessionFact ...