树(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. Joyoi花店橱窗(原tyvj1124)

    题目:http://www.joyoi.cn/problem/tyvj-1124 两点注意!!! 1.滚动数组的初始化: 2.字典序操作! 感到很有趣!!! #include<iostream& ...

  2. C#设计模式之:抽象工厂模式与反射

    抽象工厂模式[实例]:定义一个用于创建对象的接口,让子类决定实例化哪一个类 UML 代码class User{    private int _id;    public int Id { get = ...

  3. Mac 下 IDEA 中 SpringBoot 如何利用 DevTool 开启热部署

    一.首先 pom.xml 中  依赖 和 构建 部分 二.IDEA 配置 注意这一步一定不要改错地方,认准 IntelliJ IDEA -> Preferences… 三.退出 IDEA 编辑器 ...

  4. Django的 admin管理工具

    admin组件使用 Django 提供了基于 web 的管理工具. Django 自动管理工具是 django.contrib 的一部分.你可以在项目的 settings.py 中的 INSTALLE ...

  5. couldn't launch the emulator make sure the sdk directory is properly setup

    android sdk 路径中不能有空格.转到一个没有空格的文件夹下即可.

  6. win xp 安装 VS2010 时要重启是因为没安装WINDOWS INSTALLER 4.5

    win xp 安装 VS2010 时要重启是因为没安装WINDOWS INSTALLER 4.5. 无意间看到VS2010安装列表中有一项是 WINDOWS INSTALLER 4.5 . 装这个玩意 ...

  7. wxWidgets:简单消息处理

    早期的wxWidgets使用类似MFC的方式进行消息处理:在新版中这种映射方式仍然得以保留. 在MyFrame.h中添加: private: void OnQuitButton(wxCommandEv ...

  8. python使用smtplib发送邮件

    python要实现发送邮件的功能,需要使用smtplib库. 1. 过程大致如下: 1. 建立和SMTP邮件服务器的连接 # 默认端口25 smtp = smtplib.SMTP(host, port ...

  9. php提交表单校验例子

    <!DOCTYPE HTML> <meta http-equiv="Content-Type" content="text/html; charset= ...

  10. SpringBoot 自定义线程池

    本教程目录: 自定义线程池 配置spring默认的线程池 1. 自定义线程池 1.1 修改application.properties task.pool.corePoolSize=20 task.p ...