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 相关文章推荐
浅谈Javascript Base64 加密解密
Dec 28 Javascript
jQuery使用fadein方法实现渐出效果实例
Mar 27 Javascript
js跨域请求的5中解决方式
Jul 02 Javascript
jquery实现图片上传之前预览的方法
Jul 11 Javascript
Javascript动画效果(4)
Oct 11 Javascript
JS中数组重排序方法
Nov 11 Javascript
React实现点击删除列表中对应项
Jan 10 Javascript
详解node Async/Await 更好的异步编程解决方案
May 10 Javascript
浅谈微信小程序列表埋点曝光指南
Oct 15 Javascript
Angular 多模块项目构建过程
Feb 13 Javascript
javascript 使用sleep函数的常见方法详解
Apr 26 Javascript
el-table-column 内容不自动换行的解决方法
Aug 14 Vue.js
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实现)只使用++运算实现加法,减法,乘法,除法
2013/06/27 PHP
php 数组处理函数extract详解及实例代码
2016/11/23 PHP
菜鸟javascript基础整理1
2010/12/06 Javascript
jQuery菜单插件superfish使用指南
2015/04/21 Javascript
jQuery简单操作cookie的插件实例
2016/01/13 Javascript
js实现精确到秒的日期选择器完整实例
2016/04/30 Javascript
JS实现放大、缩小及拖拽图片的方法【可兼容IE、火狐】
2016/08/23 Javascript
简单的js表格操作
2016/09/24 Javascript
js实现对table的增加行和删除行的操作方法
2016/10/13 Javascript
Bootstrap table右键功能实现方法
2017/02/20 Javascript
Parcel 打包示例(React HelloWorld)
2018/01/16 Javascript
element-ui 设置菜单栏展开的方法
2018/08/22 Javascript
vue router总结 $router和$route及router与 router与route区别
2019/07/05 Javascript
JavaScript检测是否开启了控制台(F12调试工具)
2020/10/02 Javascript
[41:21]夜魇凡尔赛茶话会 第三期02:看图识人
2021/03/11 DOTA
400多行Python代码实现了一个FTP服务器
2012/05/10 Python
使用scrapy实现爬网站例子和实现网络爬虫(蜘蛛)的步骤
2014/01/23 Python
简单的通用表达式求10乘阶示例
2014/03/03 Python
python根据开头和结尾字符串获取中间字符串的方法
2015/03/26 Python
浅谈Python用QQ邮箱发送邮件时授权码的问题
2018/01/29 Python
Python星号*与**用法分析
2018/02/02 Python
python实现Adapter模式实例代码
2018/02/09 Python
Flask使用Pyecharts在单个页面展示多个图表的方法
2019/08/05 Python
Python 使用 docopt 解析json参数文件过程讲解
2019/08/13 Python
HTML5 placeholder属性详解
2016/06/22 HTML / CSS
英国美发和美容产品商城:HQhair
2019/02/08 全球购物
艺术家策划的室内设计:Curious Egg
2019/03/06 全球购物
酒店管理专业毕业生推荐信
2013/11/10 职场文书
总经理助理的八要求
2013/11/12 职场文书
《满井游记》教学反思
2014/02/26 职场文书
公司开业庆典主持词
2014/03/21 职场文书
2015年度房地产工作总结
2015/04/09 职场文书
2015年技术员工作总结
2015/04/10 职场文书
2015年乡镇民政工作总结
2015/05/13 职场文书
2015年数学教师工作总结
2015/05/20 职场文书
入党积极分子考察意见
2015/06/02 职场文书