树?二叉树?二叉搜索树BST(二叉树)
树
树(Tree): n(n≥0)个结点构成的有限集合。
- 当n=0时,称为空树;
- 对于任一棵非空树(n> 0),它具备以下性质:
- 树中有一个称为“根(Root)”的特殊结点,用 root 表示;
- 其余结点可分为m(m>0)个互不相交的有限集T1,T2,... ,Tm,其中每个集合本身又是一棵树,称为原来树的“子树(SubTree)”
注意:
- 子树之间不可以相交
- 除了根结点外,每个结点有且仅有一个父结点;
- 一棵N个结点的树有N-1条边。
树的术语:
1.结点的度(Degree):结点的子树个数.
2.树的度:树的所有结点中最大的度数. (树的度通常为结点的个数N-1)
3.叶结点(Leaf):度为0的结点. (也称为叶子结点)
4.父结点(Parent):有子树的结点是其子树的根结点的父结点
5.子结点(Child):若A结点是B结点的父结点,则称B结点是A结点的子结点;子结点也称孩子结点。
6.兄弟结点(Sibling):具有同一父结点的各结点彼此是兄弟结点。
7.路径和路径长度:从结点n1到nk的路径为一个结点序列n1 , n2,… , nk, ni是 ni+1的父结点。路径所包含边的个数为路径的长度。
8.结点的层次(Level):规定根结点在1层,其它任一结点的层数是其父结点的层数加1。
什么是二叉树?
-
二叉树可以为空, 也就是没有结点.
-
二叉树的特性
- 一个二叉树第 i 层的最大结点数为:2^(i-1), i >= 1;
- 深度为k的二叉树有最大结点总数为: 2^k - 1, k >= 1;
- 对任何非空二叉树 T,若n0表示叶结点的个数、n2是度为2的非叶结点个数,那么两者满足关系n0 = n2 + 1。
特殊的二叉树
-
完美二叉树(Perfect Binary Tree) , 也称为满二叉树(Full Binary Tree)
-
在二叉树中, 除了最下一层的叶结点外, 每层节点都有2个子结点, 就构成了满二叉树.
-
-
完全二叉树(Complete Binary Tree)
-
除二叉树最后一层外, 其他各层的节点数都达到最大个数.
-
且最后一层从左向右的叶结点连续存在, 只缺右侧若干节点.
-
完美二叉树是特殊的完全二叉树.
二叉树的存储
-
二叉树的存储常见的方式是链表.
-
链表存储:
-
二叉树最常见的方式还是使用链表存储.
-
每个结点封装成一个Node, Node中包含存储的数据, 左结点的引用, 右结点的引用.
二叉搜索时的实现
前序遍历,中序遍历,后序遍历、寻找最值、删除节点、搜索节点
class Node { constructor(data) { this.left = null; this.data = data; this.right = null; } } class BST { constructor() { this.root = null; } // 1.插入 insert(ele) { // 创建新节点 let newnode = new Node(ele); // console.log(newnode); if (this.root == null) { // 空树 this.root = newnode } else { this.insertNode(this.root, newnode) } } insertNode(root, newnode) { if (newnode.data < root.data) { // 放左边 if (root.left == null) { root.left = newnode } else { this.insertNode(root.left, newnode) } } else { //放右边 if (root.right == null) { root.right = newnode } else { this.insertNode(root.right, newnode) } } } // 2.前序遍历 preOrderTraversal() { this.preOrderTraversalNode(this.root) } preOrderTraversalNode(root) { if (root != null) { // {left:node,data:11,right:node} != null // 1.根 console.log(root.data); //11 7 15 // 2.前序遍历左子树 this.preOrderTraversalNode(root.left) // 3.前序遍历右子树 this.preOrderTraversalNode(root.right) } } // 3.中序遍历 inOrderTraversal() { this.inOrderTraversalNode(this.root) } inOrderTraversalNode(root) { if (root != null) { // 1.中序遍历左子树 this.inOrderTraversalNode(root.left) // 2.根 console.log(root.data); // 3.中序遍历右子树 this.inOrderTraversalNode(root.right) } } // 4.后序遍历 postOrderTraversal() { this.postOrderTraversalNode(this.root) } postOrderTraversalNode(root) { if (root != null) { // 1.后序遍历左子树 this.postOrderTraversalNode(root.left) // 2.后序遍历右子树 this.postOrderTraversalNode(root.right) // 3.根 console.log(root.data); } } // 5.最值 getMin() { if (this.root == null) { return } else { let current = this.root; while (current.left != null) { current = current.left } return current.data } } getMax() { if (this.root == null) { return } else { let current = this.root; while (current.right != null) { current = current.right } return current.data } } remove(ele) { if (this.root == null) return let current = this.root, parent, isLeftChild; // 找到删除节点和父节点,判断是左子节点吗? while (ele != current.data) { if (ele < current.data) { //左边找 parent = current; current = current.left; isLeftChild = true; } else { parent = current; current = current.right; isLeftChild = false; } } let delNode = current; // console.log(`当前删除的元素是${current.data},删除元素的父节点是${parent.data},是左孩子吗?${isLeftChild}`); // 1.删除叶结点 左右子树都为空 if (delNode.left == null && delNode.right == null) { if (delNode == this.root) { this.root = null; } else { if (isLeftChild) { //左孩子 parent.left = null; } else { parent.right = null; } } } else if (delNode.left != null && delNode.right == null) { //2.只有一个左子节点的节点 if (delNode == this.root) { this.root = delNode.left } else { if (isLeftChild) { parent.left = delNode.left } else { parent.right = delNode.left } } } else if (delNode.left == null && delNode.right != null) { //只有一个右子节点的节点 if (delNode == this.root) { this.root = delNode.right } else { if (isLeftChild) { parent.left = delNode.right } else { parent.right = delNode.right } } } else { //删除有两个子节点 let houji = this.gethouji(delNode);//后继为右子树中的最小值 if (delNode == this.root) { this.root = houji; } else { if (isLeftChild) { parent.left = houji; } else { parent.right = houji; } } houji.left = delNode.left; } } gethouji(delNode) { let current = delNode.right; //后继 let houjiparent = delNode; while (current.left != null) { houjiparent = current; current = current.left; } if (current != delNode.right) { //当后继为删除节点的右节点 houjiparent.left = current.right; current.right = delNode.right } return current } seacrh(ele) { if (this.root == null) return let current = this.root; while (current) { if (ele < current.data) { //左边找 current = current.left } else if (ele > current.data) { current = current.right; } else { return true } } return false } } let bst = new BST(); bst.insert(11) bst.insert(7) bst.insert(15) bst.insert(5) bst.insert(3) bst.insert(9) bst.insert(8) bst.insert(10) bst.insert(13) bst.insert(12) bst.insert(14) bst.insert(20) bst.insert(18) bst.insert(25) bst.insert(19) console.log(bst.seacrh(9)); console.log(bst.seacrh(100)); console.log(bst);