树
- ⾮线性的存储结构
- 存储的是具有⼀对多的关系的数据元素的集合
树的结点
- 结点:使⽤树结构存储的每⼀个数据元素都被称为“结点”。例如图中的A就是⼀个结点。
- 根结点:有⼀个特殊的结点,这个结点没有前驱,我们将这种结点称之为根结点。
- ⽗结点(双亲结点)、⼦结点和兄弟结点:对于ABCD四个结点来说,A就是BCD的⽗结点,也称之为双亲结点。⽽BCD都是A的⼦结点,也称之为孩⼦结点。对于BCD来说,因为他们都有同⼀个爹,所以它们互相称之为兄弟结点。
- 叶⼦结点:如果⼀个结点没有任何⼦结点,那么此结点就称之为叶⼦结点。
- 结点的度:结点拥有的⼦树的个数,就称之为结点的度。
- 树的度:在各个结点当中,度的最⼤值。为树的度。
- 树的深度或者⾼度:结点的层次从根结点开始定义起,根为第⼀层,根的孩⼦为第⼆层。依次类 推。
树的存储结构
双亲表示法
//Node结点
public class Node {
//树种存放的数据
int data;
//该结点的⽗节点在数组中的下标位置
int parent;
public Node(int data,int index){
this.data = data;
this.parent = index;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public int getParent() {
return parent;
}
public void setParent(int parent) {
this.parent = parent;
}
}
//双亲表示法
public class TreeParentDemo {
Node node[];
int size;//当前元素个数
int maxSize;//当前最⼤元素个数
public TreeParentDemo(int temp){
node = new Node[temp];
this.maxSize = temp;
this.size = 0;
}
/**
* 构建跟结点
* @param data 根节点的数据
*/
public void insert(int data){
//已有根节点 ⽆法继续构建根节点
if(size > 1){
//提示
}
Node node = new Node(data,-1);
this.node[size] = node;
size++;
}
/**
* 插⼊⼦节点
* @param data 待插⼊⼦节点的数据
* @param index 该⼦节点插⼊到哪个结点下⾯
*/
public void insertSon(int data,int index){
//是否有这个⽗节点 如果没有该⽗节点 那就 提示⼀下
Node node = new Node(data,index);
this.node[size] = node;
size++;
}
public void show(){
for (int i = 0; i < size;i++){
System.out.println("数据:" + node[i].getData() + "⽗级结点为:" +
node[i].getParent());
}
}
}
//测试数据
public class Test {
public static void main(String[] args) {
TreeParentDemo demo = new TreeParentDemo(10);
demo.insert(1);
demo.insertSon(2,0);
demo.insertSon(3,0);
demo.insertSon(4,0);
demo.insertSon(7,1);
demo.show();
}
}
优缺点:
由于根结点是没有双亲的,所以我们约定根结点的位置域设置为-1,这也就意味着,我们所有的结点都存有它双亲的位置。这样的存储结构,我们可以根据结点的parent指针很容易找到它的双亲结点,所⽤的时间复杂度为O(1),直到parent为-1时,表示找到了树结点的根。
优化方法:
增加⼀个结点最左边孩⼦的域,
孩子表示法
孩子兄弟表示法
//结点
/**
* @author Turing
* @version 1.0.0
* @Description TODO
**/
public class Node {
//数据
int data;
//孩⼦指针域
Node child;
//兄弟指针域
Node sibling;
public Node(int data){
this.data = data;
}
}
public class TreeCP {
Node root;
//新增⼀个临时结点 ⽅便接收定位的数据
Node tempNode;
public TreeCP(int data){
root = new Node(data);
}
/**
* 在指定的位置添加结点
*/
public void insert(int data,int temp){
//定位到该节点
getNode(root,temp);
Node node = tempNode;
if (node == null){
System.out.println("没有结点");
} else{
if (node.child == null){
node.child = new Node(data);
}else {
Node tempNode = node.child;
Node newNode = new Node(data);
newNode.sibling = tempNode.sibling;
tempNode.sibling = newNode;
}
}
}
public void getNode(Node node,int temp){
if (node.data == temp){
tempNode = node;
}
//如果我的兄弟结点⾮空,则取出元素
if (node.sibling != null){
getNode(node.sibling,temp);
}
if (node.child != null){
getNode(node.child,temp);
}
}
}
//测试
public class Test {
public static void main(String[] args) {
TreeCP treeCP = new TreeCP(1);
treeCP.insert(2,1);
treeCP.insert(3,1);
treeCP.insert(4,2);
System.out.println(treeCP.root.child.sibling.data);
}
}
这种表示法,给查找某个结点的某个孩⼦带来了⽅便,只需要通过firstchild找到此结点的⻓⼦,然后再通过⻓⼦结点的rightsib找到它的⼆弟,接着⼀直下去,直到找到具体的孩⼦。