c#数和二叉树
树(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#数和二叉树的更多相关文章
- [ACM训练] 数据结构----树、二叉树----c++ && python
树结构,尤其是二叉树结构是算法中常遇见的,这里根据学习过程做一个总结. 二叉树所涉及到的知识点有:满二叉树与完全二叉树.节点数目的关系.节点数与二叉树高度的关系.层次遍历.深度优先遍历.广度优先遍历等 ...
- 数据结构——二叉树(Binary Trees)
非线性数据结构 二叉搜索树(Binary Search Tree) 树的密度=结点数/高度 二叉树类 #pragma once class stnode { public: int nodeValue ...
- Android版数据结构与算法(六):树与二叉树
版权声明:本文出自汪磊的博客,未经作者允许禁止转载. 之前的篇章主要讲解了数据结构中的线性结构,所谓线性结构就是数据与数据之间是一对一的关系,接下来我们就要进入非线性结构的世界了,主要是树与图,好了接 ...
- 卡特兰(Catalan)数入门详解
也许更好的阅读体验 基本概念 介绍 学卡特兰数我觉得可能比组合数要难一点,因为组合数可以很明确的告诉你那个公式是在干什么,而卡特兰数却像是在用大量例子来解释什么时卡特兰数 这里,我对卡特兰数做一点自己 ...
- Leetcode823 : 因子二叉树问题
问题描述 给定一个数组,数组中的数不重复,且均大于1.要求使用数组中的数构建二叉树,每个数字可以被重复使用,除了叶子节点,每个节点的值等于其子节点的乘积,求构建二叉树的数量,返回的结果mod 10** ...
- 数据结构(一)二叉树 & avl树 & 红黑树 & B-树 & B+树 & B*树 & R树
参考文档: avl树:http://lib.csdn.net/article/datastructure/9204 avl树:http://blog.csdn.net/javazejian/artic ...
- 二叉树&满二叉树与完全二叉树
二叉树的定义 二叉树(Binary Tree)是n(n≥0)个元素的有限集合,该集合为空或者为由一个称为"根"的元素及两个不相交的.被分别称为左子树和右子树的二叉树组成 二叉树的基 ...
- Java数据结构——树、二叉树的理论知识汇总
通用树的理论知识 一.树的定义 由一个或多个(n>=0)节点组成的有限集合T,有且仅有一个节点称为根(root),当n>1时,其7余的节点为m(m>=0)个互不相交的有限集合T1,T ...
- leetcode_二叉树篇_python
主要是深度遍历和层序遍历的递归和迭代写法. 另外注意:因为求深度可以从上到下去查 所以需要前序遍历(中左右),而高度只能从下到上去查,所以只能后序遍历(左右中). 所有题目首先考虑root否是空.有的 ...
随机推荐
- 大快DKH大数据智能分析平台监控参数说明
2018年国内大数据公司50强榜单排名已经公布了出来,大快以黑马之姿闯入50强,并摘得多项桂冠.Hanlp自然语言处理技术也荣膺了“2018中国数据星技术”奖.对这份榜单感兴趣的可以找一下看看.本篇承 ...
- 把存储过程SELECT INTO到临时表
在开发过程中,很多时候要把结果集存放到临时表中,常用的方法有两种. 一. SELECT INTO1. 使用select into会自动生成临时表,不需要事先创建12 select * into #te ...
- samba 挂载windows共享文件夹
先转载一片文章 centOS下yum安装配置samba 地址 http://blog.csdn.net/linglongwunv/article/details/5212875 遇到问题1 # ...
- git: fatal: Could not read from remote repository
This is probably an Intellij problem. Your key are managed natively by ssh, and Intellij has it's ow ...
- wxWidgets:处理wxEVT_PAINT
我们仍然以继承于wxFrame的MyFrame作为例子. MyFrame.h: class MyFrame : public wxFrame { ...... private: ...... void ...
- 在VS2013平台下如何快速解决c++代码内存泄漏问题
在学习FPS3000人脸关键点定位算法时,发现github上的源码,存在大量的内存泄漏问题,在训练的时发现内存一直在增长,测试的时候也存在内存无法彻底释放的问题. 一直以为是存放模型参数vector& ...
- linux shell 命令常用快捷键
下面是一些shell的常用快捷键,快捷键玩熟悉了在一定程度上是可以提高工作效率滴… Ctrl + a 切换到命令行开始 Ctrl + e 切换到命令行末尾 Ctrl + l 清除屏幕内容 Ctrl + ...
- Vue 组件以及生命周期函数
组件相当于母版的功能 新建.vue文件,手动完善 <template><div>根节点</div></template> <script>& ...
- 《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #20 使用fio进行I/O的基准测试
HACK #20 使用fio进行I/O的基准测试 本节介绍使用fio进行模拟各种情况的I/O基准测试的操作方法.I/O的基准测试中有无数需要考虑的因素.是I/O依次访问还是随机访问?是通过read/w ...
- 装饰模式 (Decoratory)
动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更灵活. 装饰模式就是利用 SetComponent 来对对象进行包装的,这样每个装饰对象的实现就和如何使用这个对象分离开了,每个 ...