javascript数据结构之多叉树经典操作示例【创建、添加、遍历、移除等】


Posted in Javascript onAugust 01, 2018

本文实例讲述了javascript数据结构之多叉树经典操作。分享给大家供大家参考,具体如下:

多叉树可以实现复杂的数据结构的存储,通过遍历方法可以方便高效的查找数据,提高查找的效率,同时方便管理节点数据。javascript的DOM其实就是以多叉树的形式存储的。下面用javascript来实现多叉树的数据结构

1、创造一个节点

数据是以节点的形式存储的:

class Node {
  constructor(data) {
    this.data = data;
    this.parent = null;
    this.children = [];
  }
}

2、创造树

树用来连接节点,就像真实世界树的主干一样,延伸着很多分支

class MultiwayTree {
  constructor() {
    this._root = null;
  }
}

3、添加一个节点

function add(data, toData, traversal) {
  let node = new Node(data)
  // 第一次添加到根节点
  // 返回值为this,便于链式添加节点
  if (this._root === null) {
    this._root = node;
    return this;
  }
  let parent = null,
    callback = function(node) {
      if (node.data === toData) {
        parent = node;
        return true;
      }
    };
  // 根据遍历方法查找父节点(遍历方法后面会讲到),然后把节点添加到父节点
  // 的children数组里
  // 查找方法contains后面会讲到
  this.contains(callback, traversal);
  if (parent) {
    parent.children.push(node);
    node.parent = parent;
    return this;
  } else {
    throw new Error('Cannot add node to a non-existent parent.');
  }
}

4、深度优先遍历

深度优先会尽量先从子节点查找,子节点查找完再从兄弟节点查找,适合数据深度比较大的情况,如文件目录

function traverseDF(callback) {
  let stack = [], found = false;
  stack.unshift(this._root);
  let currentNode = stack.shift();
  while(!found && currentNode) {
    // 根据回调函数返回值决定是否在找到第一个后继续查找
    found = callback(currentNode) === true ? true : false;
    if (!found) {
      // 每次把子节点置于堆栈最前头,下次查找就会先查找子节点
      stack.unshift(...currentNode.children);
      currentNode = stack.shift();
    }
  }
}

5、广度优先遍历

广度优先遍历会优先查找兄弟节点,一层层往下找,适合子项较多情况,如公司岗位级别

function traverseBF(callback) {
  let queue = [], found = false;
  queue.push(this._root);
  let currentNode = queue.shift();
  while(!found && currentNode) {
    // 根据回调函数返回值决定是否在找到第一个后继续查找
    found = callback(currentNode) === true ? true : false;
    if (!found) {
      // 每次把子节点置于队列最后,下次查找就会先查找兄弟节点
      queue.push(...currentNode.children)
      currentNode = queue.shift();
    }
  }
}

6、包含节点

function contains(callback, traversal) {
  traversal.call(this, callback);
}

回调函数算法可自己根据情况实现,灵活度较高

7、移除节点

// 返回被移除的节点
function remove(data, fromData, traversal) {
  let parent = null,
    childToRemove = null,
    callback = function(node) {
      if (node.data === fromData) {
        parent = node;
        return true;
      }
    };
  this.contains(callback, traversal);
  if (parent) {
    let index = this._findIndex(parent.children, data);
    if (index < 0) {
      throw new Error('Node to remove does not exist.');
    } else {
      childToRemove = parent.children.splice(index, 1);
    }
  } else {
    throw new Error('Parent does not exist.');
  }
  return childToRemove;
}

_findIndex实现:

function _findIndex(arr, data) {
  let index = -1;
  for (let i = 0, len = arr.length; i < len; i++) {
    if (arr[i].data === data) {
      index = i;
      break;
    }
  }
  return index;
}

完整算法

class Node {
  constructor(data) {
    this.data = data;
    this.parent = null;
    this.children = [];
  }
}
class MultiwayTree {
  constructor() {
    this._root = null;
  }
  //深度优先遍历
  traverseDF(callback) {
    let stack = [], found = false;
    stack.unshift(this._root);
    let currentNode = stack.shift();
    while(!found && currentNode) {
      found = callback(currentNode) === true ? true : false;
      if (!found) {
        stack.unshift(...currentNode.children);
        currentNode = stack.shift();
      }
    }
  }
  //广度优先遍历
  traverseBF(callback) {
    let queue = [], found = false;
    queue.push(this._root);
    let currentNode = queue.shift();
    while(!found && currentNode) {
      found = callback(currentNode) === true ? true : false;
      if (!found) {
        queue.push(...currentNode.children)
        currentNode = queue.shift();
      }
    }
  }
  contains(callback, traversal) {
    traversal.call(this, callback);
  }
  add(data, toData, traversal) {
    let node = new Node(data)
    if (this._root === null) {
      this._root = node;
      return this;
    }
    let parent = null,
      callback = function(node) {
        if (node.data === toData) {
          parent = node;
          return true;
        }
      };
    this.contains(callback, traversal);
    if (parent) {
      parent.children.push(node);
      node.parent = parent;
      return this;
    } else {
      throw new Error('Cannot add node to a non-existent parent.');
    }
  }
  remove(data, fromData, traversal) {
    let parent = null,
      childToRemove = null,
      callback = function(node) {
        if (node.data === fromData) {
          parent = node;
          return true;
        }
      };
    this.contains(callback, traversal);
    if (parent) {
      let index = this._findIndex(parent.children, data);
      if (index < 0) {
        throw new Error('Node to remove does not exist.');
      } else {
        childToRemove = parent.children.splice(index, 1);
      }
    } else {
      throw new Error('Parent does not exist.');
    }
    return childToRemove;
  }
  _findIndex(arr, data) {
    let index = -1;
    for (let i = 0, len = arr.length; i < len; i++) {
      if (arr[i].data === data) {
        index = i;
        break;
      }
    }
    return index;
  }
}

控制台测试代码

var tree = new MultiwayTree();
tree.add('a')
  .add('b', 'a', tree.traverseBF)
  .add('c', 'a', tree.traverseBF)
  .add('d', 'a', tree.traverseBF)
  .add('e', 'b', tree.traverseBF)
  .add('f', 'b', tree.traverseBF)
  .add('g', 'c', tree.traverseBF)
  .add('h', 'c', tree.traverseBF)
  .add('i', 'd', tree.traverseBF);
console.group('traverseDF');
tree.traverseDF(function(node) {
  console.log(node.data);
});
console.groupEnd('traverseDF');
console.group('traverseBF');
tree.traverseBF(function(node) {
  console.log(node.data);
});
console.groupEnd('traverseBF');
// 深度优先查找
console.group('contains1');
tree.contains(function(node) {
  console.log(node.data);
  if (node.data === 'f') {
    return true;
  }
}, tree.traverseDF);
console.groupEnd('contains1')
// 广度优先查找
console.group('contains2');
tree.contains(function(node) {
  console.log(node.data);
  if (node.data === 'f') {
    return true;
  }
}, tree.traverseBF);
console.groupEnd('contains2');
tree.remove('g', 'c', tree.traverseBF);

这里使用在线HTML/CSS/JavaScript代码运行工具:http://tools.3water.com/code/HtmlJsRun测试运行效果如下:

javascript数据结构之多叉树经典操作示例【创建、添加、遍历、移除等】

感兴趣的朋友可以自己测试一下看看运行效果。

希望本文所述对大家JavaScript程序设计有所帮助。

Javascript 相关文章推荐
Ext面向对象开发实践(续)
Nov 18 Javascript
基于jQuery的淡入淡出可自动切换的幻灯插件打包下载
Sep 15 Javascript
为jQuery增加join方法的实现代码
Nov 28 Javascript
javascript中onmouse事件在div中失效问题的解决方法
Jan 09 Javascript
用js代码改变单选框选中状态的简单实例
Dec 18 Javascript
javascript实现label标签跳出循环操作
Mar 06 Javascript
jquery实现下拉框功能效果【实例代码】
May 06 Javascript
security.js实现的RSA加密功能示例
Jun 06 Javascript
JavaScript实现单英文金山打字通
Jul 24 Javascript
javascript严格模式详解(含严格模式与非严格模式的区别)
Nov 12 Javascript
整理 node-sass 安装失败的原因及解决办法(小结)
Feb 19 Javascript
jQuery实现鼠标放置名字上显示详细内容气泡提示框效果的方法分析
Apr 04 jQuery
JavaScript事件冒泡与事件捕获实例分析
Aug 01 #Javascript
JS+HTML实现的圆形可点击区域示例【3种方法】
Aug 01 #Javascript
create-react-app 修改为多入口编译的方法
Aug 01 #Javascript
Vue项目全局配置页面缓存之按需读取缓存的实现详解
Aug 01 #Javascript
JavaScript执行环境及作用域链实例分析
Aug 01 #Javascript
Vue.js 利用v-for中的index值实现隔行变色
Aug 01 #Javascript
echarts设置图例颜色和地图底色的方法实例
Aug 01 #Javascript
You might like
PHP框架自动加载类文件原理详解
2017/06/06 PHP
thinkPHP中U方法加密传递参数功能示例
2018/05/29 PHP
PHP实现微信提现功能(微信商城)
2019/11/21 PHP
Javascript Math对象
2009/08/13 Javascript
js Function类型
2011/12/04 Javascript
jquery 合并内容相同的单元格(示例代码)
2013/12/13 Javascript
JavaScript中数据结构与算法(一):栈
2015/06/19 Javascript
js密码强度校验
2015/11/10 Javascript
基于Javascript实现返回顶部按钮
2016/02/29 Javascript
JS前向后瞻正则表达式定义与用法示例
2016/12/27 Javascript
jQuery插件echarts去掉垂直网格线用法示例
2017/03/03 Javascript
es6学习笔记之Async函数基本教程
2017/05/11 Javascript
vue.js打包之后可能会遇到的坑!
2018/06/03 Javascript
Bootstrap Fileinput 4.4.7文件上传实例详解
2018/07/25 Javascript
微信小程序CSS3动画下拉菜单效果
2018/11/04 Javascript
vue中created和mounted的区别浅析
2019/08/13 Javascript
CKEditor扩展插件:自动排版功能autoformat插件实现方法详解
2020/02/06 Javascript
微信小程序仿通讯录功能
2020/04/09 Javascript
Python使用turtule画五角星的方法
2015/07/09 Python
python中获得当前目录和上级目录的实现方法
2017/10/12 Python
Python cookbook(数据结构与算法)让字典保持有序的方法
2018/02/18 Python
Python打印输出数组中全部元素
2018/03/13 Python
python实现机器学习之多元线性回归
2018/09/06 Python
Python使用while循环花式打印乘法表
2019/01/28 Python
对Python的交互模式和直接运行.py文件的区别详解
2019/06/29 Python
PyTorch中topk函数的用法详解
2020/01/02 Python
免税水晶:Duty Free Crystal
2019/05/13 全球购物
亚洲颇具影响力的男性在线购物零售商:His
2019/11/24 全球购物
企业安全生产标语
2014/06/06 职场文书
争先创优心得体会
2014/09/12 职场文书
2014房屋登记授权委托书
2014/10/13 职场文书
大一新生军训新闻稿
2015/07/17 职场文书
2019最新公司租房合同(例文)
2019/07/18 职场文书
使用python如何删除同一文件夹下相似的图片
2021/05/07 Python
Python Pandas pandas.read_sql_query函数实例用法分析
2021/06/21 Python
php解析非标准json、非规范json的方式实例
2022/05/10 PHP