树
二叉树
二叉树的存储可以用数组(完全二叉树)也可以用链表(推荐)
二叉搜索树
所有的左子树都小于根节点,所有的右子树都大于根节点
其实就是二分法转化成二叉树结构,但是最开始的数可能不是最中间的数
二叉搜索树的代码封装
function BinarySerachTree() {
function Node(key) {
this.key = key;
this.left = null;
this.right = null;
}
// 自身的属性
this.root = null;
// 方法
BinarySerachTree.prototype.insert = function (key) {
//第一个插入的肯定是根,后续的
//先创建新节点
let newNode = new Node(key);
if (this.root==null) {
this.root = newNode;
}else{
this.insertNode(this.root, newNode)
}
}
// 往树的深处查找的递归函数
BinarySerachTree.prototype.insertNode = function (node, newNode) {
//第一个参数是root, 第二个参数是新节点
if (newNode.key < node.key) {
//向左
if (node.left == null) {
node.left = newNode;
}else{
this.insertNode(node.left, newNode);
}
}else{
//向右查找
if (node.right == null) {
node.right = newNode;
}else{
this.insertNode(node.right, newNode);
}
}
}
// 二叉树的遍历
// 1. 先序遍历
BinarySerachTree.prototype.preOrderTraversal = function (handler) {
this.preOrderTraversalNode(this.root, handler);
}
BinarySerachTree.prototype.preOrderTraversalNode = function (node, handler) {
if (node != null) {
//处理经过的节点
handler(node.key);
//处理经过节点的左子节点
this.preOrderTraversalNode(node.left, handler);
// 处理经过节点的右子节点
this.preOrderTraversalNode(node.right, handler);
}
}
// 2. 中序遍历
BinarySerachTree.prototype.midOrderTraversal = function (handler) {
this.midOrderTraversalNode(this.root, handler);
}
BinarySerachTree.prototype.midOrderTraversalNode = function (node, handler) {
if (node != null) {
//处理经过的节点
//处理经过节点的左子节点
this.midOrderTraversalNode(node.left, handler);
handler(node.key);
// 处理经过节点的右子节点
this.midOrderTraversalNode(node.right, handler);
}
}
// 3. 后序遍历
BinarySerachTree.prototype.postOrderTraversal = function (handler) {
this.postOrderTraversalNode(this.root, handler);
}
BinarySerachTree.prototype.postOrderTraversalNode = function (node, handler) {
if (node != null) {
//处理经过的节点
//处理经过节点的左子节点
this.postOrderTraversalNode(node.left, handler);
// 处理经过节点的右子节点
this.postOrderTraversalNode(node.right, handler);
handler(node.key);
}
}
// 寻找最值
BinarySerachTree.prototype.min = function () {
let node = this.root;
while(node.left != null) node = node.left;
return node.key;
}
BinarySerachTree.prototype.max = function () {
let node = this.root;
while(node.right != null) node = node.right;
return node.key;
}
// 搜索特定的值
BinarySerachTree.prototype.search = function (num) {
// this.searchNode(this.root, num);
let node = this.root;
while(node != null){
if (node.key > num) {
node = node.left;
}else if(node.key < num){
node = node.right;
}else{
return true;
}
}
return false;
}
// 删除操作
BinarySerachTree.prototype.remove = function (num) {
let node = this.root;
let prenode = null;//父节点的前一个是null
let flag = 0;//0默认最后向左找,1表示向右找
while(node.key != num){
//为了找到节点
prenode = node;
if (node.key > num) {
flag = 0;
node = node.left;
}else{
flag = 1;
node = node.right;
}
if (node == null) return false;//没有找到节点
}
// 没有子节点
if (node.left == null && node.right == null) {
if (node == this.root) {
//如果找到的叶子节点也是根节点
this.root = null;
}
if (flag) {
prenode.right = null;
}else{
prenode.left = null;
}
}
// 有一个子节点
else if (node.left == null) {
//有一个子节点
if (node == this.root) {
//如果是只有一个子节点的根节点
this.root = node.right;
}else if (flag) {
prenode.right = node.right;
}else{
prenode.left = node.right;
}
}else if(node.right == null){
if (node == this.root) {
//如果是只有一个子节点的根节点
this.root = node.left;
}else if (flag) {
prenode.right = node.left;
}else{
prenode.left = node.left;
}
}
// 有两个子节点,找左子树最大的或者右子树最小的,也就是那个节点的前驱或者后继
else{
let successor = this.getSuccessor(node);
if (this.root == node) {
//如果是根节点
this.root = successor;
}else if (flag) {
prenode.right = successor;
}else{
prenode.left = successor;
}
successor.left = node.left;
}
}
// 寻找后继,就是右子树中最小的
BinarySerachTree.prototype.getSuccessor = function (delnode) {
let successor = delnode;
let current = delnode.right;
let presuccessor = delnode;
while(current != null){
presuccessor = successor;
successor = current;
current = current.right;
}
if (successor != delnode.right) {
presuccessor.left = successor.right;
successor.right = delnode.right;
}
return successor;
}
}
let tree = new BinarySerachTree();
tree.insert(9);
tree.insert(10);
tree.insert(8);
tree.insert(7);
tree.insert(6);
tree.insert(0);
tree.insert(1);
tree.insert(2);
console.log(tree);
let resultString = '';
tree.postOrderTraversal(function (key) {
resultString += key + ' ';
})
alert(resultString);
二叉搜索树
在极端情况下,就相当于链表结构一样,不具备最开始说的优势之类的,比方说插入连续数据,然后就会分布不均匀,然后就成了非平衡树
为了保持优秀的搜索特性,就得让树结构趋于平衡,也就是说让树的左右子树差不多大