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 相关文章推荐
使用jquery插件实现图片延迟加载技术详细说明
Mar 12 Javascript
js 与 php 通过json数据进行通讯示例
Mar 26 Javascript
JavaScript实现文字与图片拖拽效果的方法
Feb 16 Javascript
利用transition实现文字上下抖动的效果
Jan 21 Javascript
javascript表单正则应用
Feb 04 Javascript
Bootstrap表单控件学习使用
Mar 07 Javascript
angular中的cookie读写方法
Aug 02 Javascript
微信小程序实现流程进度的图样式功能
Jan 16 Javascript
详解vue-cli3多环境打包配置
Mar 28 Javascript
vue封装可复用组件confirm,并绑定在vue原型上的示例
Oct 31 Javascript
解决vue cli4升级sass-loader(v8)后报错问题
Jul 30 Javascript
Vue 样式切换及三元判断样式关联操作
Aug 09 Javascript
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&amp;mysql(六)
2006/10/09 PHP
php下实现折线图效果的代码
2007/04/28 PHP
PHP单例模式详解及实例代码
2016/12/21 PHP
jQuery中filter()和find()的区别深入了解
2013/09/25 Javascript
javascript获取xml节点的最大值(实现代码)
2013/12/11 Javascript
js 设置缓存及获取设置的缓存
2014/05/08 Javascript
jQuery EasyUI Pagination实现分页的常用方法
2016/05/21 Javascript
jQuery实现的无限级下拉菜单功能示例
2016/09/12 Javascript
原生JS实现图片网格式渐显、渐隐效果
2017/06/05 Javascript
详解如何让Express支持async/await
2017/10/09 Javascript
QRCode.js二维码生成并能长按识别
2018/10/16 Javascript
JS动画实现回调地狱promise的实例代码详解
2018/11/08 Javascript
解决layui动态添加的元素click等事件触发不了的问题
2019/09/20 Javascript
微信小程序返回上一页传参并刷新过程解析
2019/12/13 Javascript
前端使用crypto.js进行加密的函数代码
2020/08/16 Javascript
Python字符串拼接六种方法介绍
2017/12/18 Python
python写一个md5解密器示例
2018/02/23 Python
python使用opencv按一定间隔截取视频帧
2018/03/06 Python
对python中的argv和argc使用详解
2018/12/15 Python
python中pytest收集用例规则与运行指定用例详解
2019/06/27 Python
Selenium常见异常解析及解决方案示范
2020/04/10 Python
python中return如何写
2020/06/18 Python
Python面向对象多态实现原理及代码实例
2020/09/16 Python
python 实现一个简单的线性回归案例
2020/12/17 Python
CSS3实现大小不一的粒子旋转加载动画
2016/04/21 HTML / CSS
HTML5和CSS3实例教程总结(推荐)
2016/07/18 HTML / CSS
DKNY品牌官网:纽约大都会时尚风格
2016/10/20 全球购物
亚历山大·王官网:Alexander Wang
2017/06/23 全球购物
新奥尔良珠宝:Mignon Faget
2020/11/23 全球购物
二年级班级文化建设方案
2014/05/10 职场文书
态度决定一切演讲稿
2014/05/20 职场文书
查摆问题对照检查材料
2014/08/28 职场文书
2014年教研组工作总结
2014/11/26 职场文书
2014流动人口计划生育工作总结
2014/12/20 职场文书
体育教师个人工作总结
2015/02/09 职场文书
vue配置型表格基于el-table拓展之table-plus组件
2022/04/12 Vue.js