C++树结构

树是什么

在计算机科学中,树(英语:tree)是一种抽象数据类型(ADT)或是实作这种抽象数据类型的数据结构,用来模拟具有树状结构性质的数据集合。它是由n(n>0)个有限节点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:

  • 每个节点有零个或多个子节点(child)

  • 没有父节点(parent)的节点称为根节点

  • 每一个非根节点有且只有一个父节点

  • 除了根节点(root)外,每个子节点可以分为多个不相交的子树

以上引自维基,没看懂?呵呵,其实我猛地也没看懂,只不过当你初步理解时,维基的解释比我的好:
首先明白一点,树是一种容器,类似于vector,deque之类的用于储存的容器。
其次,树结构就像真的树一样,每一个分支,也就是结点,都链接这许多分支,而树的根则是树的第一个元素,不被任何结点链接。对于一个结点来说,链接其的那个结点被称为父节点。
现在,看wiki吧!骚年!
你可以轻易的设计出一个树来,如下:

#include<vector>

template<class t>
class tree
{
    public:
    tree<t>* father=nullptr;
    std::vector<tree<t>> farq;
};

我可没有恶意命名的习惯=-=
以上就是除了数据结构以外啥也没的tree类,当然,我们接下来的任务就是设计完整。
设计完整当然需要了解些术语:

术语

Root根

顶端结点 The top node in a tree.

 Child子节点

一个结点所连接的结点 A node directly connected to another node when moving away from the Root.

Parent父节点

连接子节点的节点 The converse notion of a child.

Siblings同胞

一群有相同父节点的节点A group of nodes with the same parent.

Descendant后裔

一个父节点的子孙们A node reachable by repeated proceeding from parent to child.

Ancestor祖先

一个结点的爹,爷,祖宗们A node reachable by repeated proceeding from child to parent.

Leaf叶

一个没孩子的爹没有子节点的节点(less commonly called External node)
A node with no children.

Branch分支

有至少一个子节点的连接Internal node
A node with at least one child.

Degree度

维基上那么翻译的,degree本身的意思有度

一个节点的子树的节点的数量The number of sub trees of a node.

Edge连接

节点之间的联系The connection between one node and another.

Path路径

一个节点和祖先间的连接和节点A sequence of nodes and edges connecting a node with a descendant.

Level层次

根到该节点的连接数量+1即为层次数The level of a node is defined by 1 + (the number of connections between the node and the root).

Height of node节点高度

从该节点到该节点往下连接的最长路径的连接的数量The height of a node is the number of edges on the longest path between that node and a leaf.

Height of tree树高

树高即为根所连接的最长路径下的节点的层次The height of a tree is the height of its root node.

Depth深度

深度就是一个节点的层次The depth of a node is the number of edges from the tree’s root node to the node.

Forest森林

由不相交的树组成的集合叫森林A forest is a set of n ≥ 0 disjoint trees.

树的种类

树有许多种类,如下,引自维基:
- 无序树:树中任意节点的子节点之间没有顺序关系,这种树称为无序树,也称为自由树;
- 有序树:树中任意节点的子节点之间有顺序关系,这种树称为有序树;
- 二叉树:每个节点最多含有两个子树的树称为二叉树;
- 完全二叉树:对于一颗二叉树,假设其深度为d(d>1)。除了第d层外,其它各层的节点数目均已达最大值,且第d层所有节点从左向右连续地紧密排列,这样的二叉树被称为完全二叉树;
- 满二叉树:所有叶节点都在最底层的完全二叉树;
- 平衡二叉树(AVL树):当且仅当任何节点的两棵子树的高度差不大于1的二叉树;
- 排序二叉树(二叉查找树(英语:Binary Search Tree),也称二叉搜索树、有序二叉树);
- 霍夫曼树:带权路径最短的二叉树称为哈夫曼树或最优二叉树;
- B树:一种对读写操作进行优化的自平衡的二叉查找树,能够保持数据有序,拥有多余两个子树。
如上即为树的种类,下面,我们看树的实现——

树的实现

我们先定个小目标,比如挣它一个亿如下:
1.构造空树
2.构造树
3.判断树是否为空
4.获取树的深度
5.获取根节点
6.获取第i个节点的值
7.改变节点的值
8.获取节点的父节点
9.获取节点的最左孩子节点
10.获取节点的右兄弟节点
11.输出树
12.向树中插入另一棵树
13.删除子树
14.层序遍历树

一个一个来,放心保证一个不落下,不过我只写函数,看类的话,整个都放在最后

1.构造空树

//由于实现是用vector容器,该步很简单
tree()
{}

2.构造树

我们的确可以使用不定参数,只不过如果我们用不定参数,必须用递归。所以,我们还是设计一个好用点的方法,只能构造一层。
是的你没听错,如果你想玩递归?抱歉,本人极其不喜欢递归的低效率。所以,在能确定层数的情况下自己再构造一层再使用该还是即可,毕竟,那写了public几个大字

tree(std::vector<t> ax)
{
farq.clean();
size=ax.size();
for(size_t i=0;i<size;i++)
{
farq.push_back(ax[i]);
farq[i].father=this;
}
}

我承认,这也很低效,但是总比递归好=-=

3.判断树是否为空

如此简单我都懒得写,只不过为了客官您,哎……

bool isnothing()
{
return (farq.size()==0)?true:false;
}

4.获取树的深度

这可不是好活,我们需要搜索算法帮忙,然而作为小白,我只能遍历了

//除了递归我别无选择……我承认我自己打自己脸
private:
void depch(size_t& num,size_t cen)
{
size_t size=farq.size();
for(size_t i=0;i<size;i++)
{
if(!farq[i].isnothing)
{
cen++
num=(num<cen)?cen:num;
farq[i].depch(num,cen);
}
}
}
public:
size_t level()
{
size_t num=0,size_t cen=0;
return depch(num,cen);
}

不过有个好消息,搜素算法对于特殊树有许多优化方式,然而那是特殊树

5.获取根

father指针真管用

tree<t> root()
{
back=this;
tree<t>* ptr=father;
while(ptr!=nullptr)
{
back=ptr;
ptr=father->father;
}
return back;
}

6.获取第i个节点的值

抱歉,这你要是不会,你可以回去复习《c++primer》了,至于为什么有这一步?wiki上有啊!

7.

我突然发现原来到11.都是很简单的操纵……抱歉抱歉,只不过那些操纵很基本,你知道也无妨。

12.插入树

这其实就是list的问题转化到vector,我们要是知道vector的内部结构那么速度会很快,然而……

void insert(tree<t> ax,size_t ix)//ax为要插入的树,i为要插入的地方,即插入后的位置
{
    farq.push_back(farq[farq.size()-1]);
    for(size_t i=farq.size()-1;i>ix;i--)
    {
        farq[i]=farq[i-1];
    }
    farq[ix]=ax;
}

13.删除树

void delete(size_t i)//i为要删除的地方,即插入后的位置
{
    size_t size=farq.size();
    for(;i<size;i++)
    {
        farq[i]=farq[i+1];
    }
    farq.pop_back();
}

14.简单的要命

下面便是更重要的运算符环节:

运算符

void operator=(tree<t> ax)
{
    father=ax.father;
    farq=ax.farq;
}
bool operator==(tree<t> ax)
{
    return ((father==ax.father)&&(farq==ax.farq));
}
bool operator!=(tree<t> ax)
{
    return !((father==ax.father)&&(farq==ax.farq));
}

好了,到此,树结构已经完成,常有操作也已经完成,如果你有什么想法,欢迎留言!

class tree

#include<vector>
#ifndef trees
#define trees

template<class t>
class tree
{
public:
tree()
{
}
tree(std::vector<t> ax)
{
farq.clean();
size=ax.size();
for(size_t i=0;i<size;i++)
{
farq.push_back(ax[i]);
}
}
bool isnothing()
{
return (farq.size()==0)?true:false;
}
size_t level()
{
size_t num=0,size_t cen=0;
return depch(num,cen);
}
tree<t> root()
{
back=this;
tree<t>* ptr=father;
while(ptr!=nullptr)
{
back=ptr;
ptr=father->father;
}
return back;
}
void delete(size_t i)//i为要删除的地方,即插入后的位置
{
    size_t size=farq.size();
    for(;i<size;i++)
    {
        farq[i]=farq[i+1];
    }
    farq.pop_back();
}
void insert(tree<t> ax,size_t ix)//ax为要插入的树,i为要插入的地方,即插入后的位置
{
    farq.push_back(farq[farq.size()-1]);
    for(size_t i=farq.size()-1;i>ix;i--)
    {
        farq[i]=farq[i-1];
    }
    farq[ix]=ax;
}
void operator=(tree<t> ax)
{
    father=ax.father;
    farq=ax.farq;
}
bool operator==(tree<t> ax)
{
    return ((father==ax.father)&&(farq==ax.farq));
}
bool operator!=(tree<t> ax)
{
    return !((father==ax.father)&&(farq==ax.farq));
}
tree<t>* father;
std::vector<tree<t>> farq;
private:
void depch(size_t& num,size_t cen)
{
size_t size=farq.size();
for(size_t i=0;i<size;i++)
{
if(!farq[i].isnothing)
{
cen++
num=(num<cen)?cen:num;
farq[i].depch(num,cen);
}
}
}
};

#endif
  • 20
    点赞
  • 68
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值