图的最小生成树问题
希望将所有村庄联通,花费最小
树:有向无环图
普利姆算法——加点法
克鲁斯卡尔算法——加边法
普利姆算法
- 选一个点作为起点
- 找到以当前选中点为起点路径最短的边
- 如果这个边的另一端没有被联通起来,那么就联结
- 如果这个边的另一端也早就被连进来了,则看倒数第二短的边
- 重复2-4直到所有的点都联通为止
克鲁斯卡尔算法
- 选择最短的边进行连接
- 要保证边连接的两端至少有一个点是新的要点
- 或者这个边是将两个部落进行连接的
- 重复1-3直到将所有的点都连接到一起
代码实现
表示一个图,可以使用点集合和边集合
点集合:[a,b,c,d,e,f]
A | B | C | D | E | |
---|---|---|---|---|---|
A | 0 | 4 | 7 | max | max |
B | 4 | 0 | 8 | 6 | max |
C | 7 | 8 | 0 | 5 | max |
D | max | 6 | 5 | 0 | 7 |
E | max | max | 7 | 0 |
var max = 1000000;
var pointSet = [];
var distance = [
[0, 4, 7, max, max],
[4, 0, 8, 6, max],
[7, 8, 0, 5, max],
[max, 6, 5, 0, 7],
[max, max, max, 7, 0]
];
function Node(value) {
this.value = value;
this.neighbor = [];
}
var a = new Node("A");
var b = new Node("B");
var c = new Node("C");
var d = new Node("D");
var e = new Node("E");
pointSet.push(a);
pointSet.push(b);
pointSet.push(c);
pointSet.push(d);
pointSet.push(e);
function getIndex(str) {
for (var i = 0; i < pointSet.length; i++) {
if (str == pointSet[i].value) return i;
}
return -1;
}
//需要传入点的集合,边的集合,当前已经连接进入的集合
// 此方法,根据当前已经有的节点,来进行判断,获取到距离最短的点
function getMinDisNode(pointSet, distance, nowPointSet) {
var fromNode = null;//线段的起点
var minDisNode = null;//线段的终点
var minDis = max;
//根据当前已有的这些点为起点,依次判断连接其他的点的距离是多少
for (var i = 0; i < nowPointSet.length; i++) {
var nowPointIndex = getIndex(nowPointSet[i].value);//获取当前节点的序号
for (var j = 0; j < distance[nowPointIndex].length; j++) {
var thisNode = pointSet[j];//thisNode表示distance中的点,但是这个点不是对象。
if (nowPointSet.indexOf(thisNode) < 0//首先这个点不能是已经接入的点
&& distance[nowPointIndex][j] < minDis) {//其次点之间的距离得是目前的最短距离
fromNode = nowPointSet[i];
minDisNode = thisNode;
minDis = distance[nowPointIndex][j];
}
}
}
fromNode.neighbor.push(minDisNode);
minDisNode.neighbor.push(fromNode);
return minDisNode;
}
function prim(pointSet, distance, start) {
var nowPointSet = [];
nowPointSet.push(start);
//获取最小代价的边
while (true) {
var minDisNode = getMinDisNode(pointSet, distance, nowPointSet);
nowPointSet.push(minDisNode);
if (nowPointSet.length == pointSet.length) {
break;
}
}
}
prim(pointSet, distance, pointSet[2]);
console.log(pointSet);
var max = 1000000;
var pointSet = [];
var distance = [
[0, 4, 7, max, max],
[4, 0, 8, 6, max],
[7, 8, 0, 5, max],
[max, 6, 5, 0, 7],
[max, max, max, 7, 0]
];
function Node(value) {
this.value = value;
this.neighbor = [];
}
var a = new Node("A");
var b = new Node("B");
var c = new Node("C");
var d = new Node("D");
var e = new Node("E");
pointSet.push(a);
pointSet.push(b);
pointSet.push(c);
pointSet.push(d);
pointSet.push(e);
function canLink(resultList, tempBegin, tempEnd) {
var beginIn = null;
var endIn = null;
for (var i = 0; i < resultList.length; i++) {
if (resultList[i].indexOf(tempBegin) > -1) {
beginIn = resultList[i];
}
if (resultList[i].indexOf(tempEnd) > -1) {
endIn = resultList[i];
}
}
//两个点都是新的点(都不在任何部落里)——可以连接,产生新的部落
// begin在A部落,end没有部落 —— A部落扩张一个村庄
// end在A部落,begin没有部落 ——A部落扩张一个村庄
// begin在A部落,end在B部落 ——将AB两个部落合并
// begin和end在同一个部落,——不可以连接
if (beginIn != null && endIn != null && beginIn == endIn) {
return false;
}
return true;
}
function link(resultList, tempBegin, tempEnd) {
var beginIn = null;
var endIn = null;
for (var i = 0; i < resultList.length; i++) {
if (resultList[i].indexOf(tempBegin) > -1) {
beginIn = resultList[i];
}
if (resultList[i].indexOf(tempEnd) > -1) {
endIn = resultList[i];
}
}
if (beginIn == null && endIn == null) {// 两个点都是新的点(都不在任何部落里)——可以连接,产生新的部落
var newArr = [];
newArr.push(tempBegin);
newArr.push(tempEnd);
resultList.push(newArr);
} else if (beginIn != null && endIn == null) {// begin在A部落,end没有部落 —— A部落扩张一个村庄
beginIn.push(tempEnd);
} else if (beginIn == null && endIn != null) {// end在A部落,begin没有部落 ——A部落扩张一个村庄
endIn.push(tempBegin);
} else if (beginIn != null && endIn != null && beginIn != endIn) {// begin在A部落,end在B部落 ——将AB两个部落合并
var allIn = beginIn.concat(endIn);
var needRemove = resultList.indexOf(endIn);
resultList.splice(needRemove, 1);
needRemove = resultList.indexOf(beginIn);
resultList.splice(needRemove, 1);
resultList.push(allIn);
}
tempBegin.neighbor.push(tempEnd);
tempEnd.neighbor.push(tempBegin);
}
function kruskal(pointSet, distance) {
var resultList = [];//这里是二维数组,此数组代表的是有多少个"部落"
while (true) {
var minDis = max;
var begin = null;
var end = null;
for (var i = 0; i < distance.length; i++) {
for (var j = 0; j < distance[i].length; j++) {
var tempBegin = pointSet[i];
var tempEnd = pointSet[j];
if (i != j//去掉自己到自己的距离,因为都为0
&& distance[i][j] < minDis
&& canLink(resultList, tempBegin, tempEnd)
) {
minDis = distance[i][j];
begin = tempBegin;
end = tempEnd;
}
}
}
link(resultList, begin, end);
if (resultList.length == 1 && resultList[0].length == pointSet.length) {//只存在一个部落
break;
}
}
}
kruskal(pointSet, distance);
console.log(pointSet);
二叉搜索树
问题:有一万个数,写一个方法,进行查找,查找给定的数,返回是否存在。尽可能性能好
var arr = [];
for (var i = 0; i < 10000; i++) {
arr[i] = Math.floor(Math.random() * 10000);
}
var num = 0;
function search(arr, target) {
for (var i = 0; i < arr.length; i++) {
num += 1;
if (arr[i] == target) return true;
}
return false;
}
console.log(search(arr, 1000));
console.log(num);
性能差:1.数据结构;2.算法
问题出在数据结构上
二叉搜索树(二叉排序树)
- 二叉树
- 有排序的效果,左子树节点都比当前节点小,右子树节点都比当前节点大
二叉搜索树
var arr = [];
for (var i = 0; i < 10000; i++) {
arr[i] = Math.floor(Math.random() * 10000);
}
function Node(value) {
this.value = value;
this.left = null;
this.right = null;
}
var num = 0;
function search(arr, target) {
for (var i = 0; i < arr.length; i++) {
num += 1;
if (arr[i] == target) return true;
}
return false;
}
function addNode(root, num) {
if (root == null) return;
if (root.value == num) return;//重复的数
if (root.value < num) {//目标值比当前节点大
if (root.right == null) root.right = new Node(num);//如果右侧为空,则创建节点
else addNode(root.right, num);//如果右侧不为空,则向右侧进行递归
} else {//目标值比当前节点小
if (root.left == null) root.left = new Node(num);
else addNode(root.left, num);
}
}
function buildSearchTree(arr) {
if (arr == null || arr.length == 0) return null;
var root = new Node(arr[0]);
for (var i = 1; i < arr.length; i++) {
addNode(root, arr[i]);
}
return root;
}
var num2 = 0;
function searchByTree(root, target) {//二叉搜索树查找过程 前序遍历
if (root == null) return false;
num2 += 1;
if (root.value == target) return true;
if (root.value > target) return searchByTree(root.left, target);
else return searchByTree(root.right, target);
}
console.log(search(arr, 1000));
console.log(num);
var root = buildSearchTree(arr);
console.log(searchByTree(root, 1000));
console.log(num2);
平衡二叉树
根节点的左子树与右子树高度差不超过1;
这颗二叉树的每个子树都符合第一条
function Node(value) {
this.value = value;
this.left = null;
this.right = null;
}
var a = new Node("a");
var b = new Node("b");
var c = new Node("c");
var d = new Node("d");
var e = new Node("e");
var f = new Node("f");
var g = new Node("g");
var h = new Node("h");
var j = new Node("j");
a.left = b;
a.right = c;
b.left = d;
// b.right = e;
c.left = f;
c.right = g;
d.right = h;
// e.right = j;
function getDeep(root) {//获取深度
if (root == null) return 0;
var leftDeep = getDeep(root.left);
var rightDeep = getDeep(root.right);
return Math.max(leftDeep, rightDeep) + 1;//加上当前一层
}
function isBalance(root) {
if (root == null) return true;
var leftDeep = getDeep(root.left);
var rightDeep = getDeep(root.right);
if (Math.abs(leftDeep - rightDeep) > 1) {//不平衡
return false;
} else {
return isBalance(root.left) && isBalance(root.right);//两边同时平衡
}
}
console.log(isBalance(b));
二叉树的单旋
不平衡变成平衡
某一节点不平衡,如果左边浅,右边深,进行左单旋
![1.png](https://img-blog.csdnimg.cn/img_convert/c4b297ecdc21203e39f54c7faeb83d77.png#height=210&id=pFOy7&margin=[object Object]&name=1.png&originHeight=560&originWidth=1168&originalType=binary&ratio=1&size=32846&status=done&style=none&width=437)
![1.png](https://img-blog.csdnimg.cn/img_convert/52e186b2cea7f9980772ee8a7c6a066f.png#height=192&id=RZBWX&margin=[object Object]&name=1.png&originHeight=388&originWidth=396&originalType=binary&ratio=1&size=11316&status=done&style=none&width=196)
旋转节点:不平衡的节点为旋转节点(2)
新根:旋转之后称为根节点的节点(5)
变化分支:父级节点发生变化的那个分支
不变分支:父级节点不变的那个分支
左单旋时:
旋转节点:当前不平衡的节点
新根:右子树的根节点
变化分支:旋转节点的右子树的左子树
不变分支:旋转节点的右子树的右子树
右单旋时:
旋转节点:当前不平衡的节点
新根:左子树的根节点
变化分支:旋转节点的左子树的右子树
不变分支:旋转节点的右子树的左子树
![1.png](https://img-blog.csdnimg.cn/img_convert/52e186b2cea7f9980772ee8a7c6a066f.png#height=192&id=NYz7F&margin=[object Object]&name=1.png&originHeight=388&originWidth=396&originalType=binary&ratio=1&size=11316&status=done&style=none&width=196)
左单旋:
- 找到新根5
- 找到变化分支
- 当前旋转节点的右子树为变化分支
- 新根的左孩子为旋转节点
- 返回新的根节点
function Node(value) {
this.value = value;
this.left = null;
this.right = null;
}
var node2 = new Node("2");
var node5 = new Node("5");
var node3 = new Node("3");
var node6 = new Node("6");
node2.right = node5;
node5.left = node3;
node5.right = node6;
function getDeep(root) {
if (root == null) return 0;
var leftDeep = getDeep(root.left);
var rightDeep = getDeep(root.right);
return Math.max(leftDeep, rightDeep) + 1;
}
function isBalance(root) {
if (root == null) return true;
var leftDeep = getDeep(root.left);
var rightDeep = getDeep(root.right);
if (Math.abs(leftDeep - rightDeep) > 1) {//不平衡
return false;
} else {
return isBalance(root.left) && isBalance(root.right);
}
}
function leftRotate(root) {
// 找到新根
var newRoot = root.right;
// 找到变化分支
var changeTree = root.right.left;
// 当前旋转节点的右孩子为变化分支
root.right = changeTree;
// 新根的左孩子为旋转节点
newRoot.left = root;
// 返回新的根节点
return newRoot;
}
function rightRotate(root) {
// 找到新根
var newRoot = root.left;
// 找到变化分支
var changeTree = root.left.right;
// 当前旋转节点的左孩子为变化分支
root.left = changeTree;
// 新根的右孩子为旋转节点
newRoot.right = root;
// 返回新的根节点
return newRoot;
}
function change(root) {//返回平衡之后的根节点
if (isBalance(root)) return root;
// 推荐用后序的方式来判断
if (root.left != null) root.left = change(root.left);// change后root就变了
if (root.right != null) root.right = change(root.right);
var leftDeep = getDeep(root.left);
var rightDeep = getDeep(root.right);
if (Math.abs(leftDeep - rightDeep) < 2) {
return true;
} else if (leftDeep > rightDeep) {//不平衡,左边深,需要右旋
return rightRotate(root);
} else {//不平衡,右边深,需要左旋
return leftRotate(root);
}
}
console.log(isBalance(node2));
var newRoot = change(node2);
console.log(isBalance(newRoot));
console.log(newRoot);
二叉树的双旋
单旋不能满足所有
![image.png](https://img-blog.csdnimg.cn/img_convert/57e095ad41ca0f2ed8b9186b0c1d461f.png#clientId=uae7afcd9-86a1-4&from=paste&height=246&id=u596fa994&margin=[object Object]&name=image.png&originHeight=492&originWidth=550&originalType=binary&ratio=1&size=19729&status=done&style=none&taskId=u931d90fc-5275-437f-8b31-9edaf0f997b&width=275)![image.png](https://img-blog.csdnimg.cn/img_convert/1f8323da5133da1903769690f509b9cc.png#clientId=uae7afcd9-86a1-4&from=paste&height=163&id=u159ee67b&margin=[object Object]&name=image.png&originHeight=325&originWidth=337&originalType=binary&ratio=1&size=17529&status=done&style=none&taskId=uc92bf097-7acb-481d-8d9d-5a5dfdf600d&width=168.5)
![image.png](https://img-blog.csdnimg.cn/img_convert/c017c6f928ec34db0d4c50de590e2c06.png#clientId=uae7afcd9-86a1-4&from=paste&height=167&id=ue3ca2cd6&margin=[object Object]&name=image.png&originHeight=334&originWidth=326&originalType=binary&ratio=1&size=22279&status=done&style=none&taskId=u1c451171-1af7-46bd-bb62-bd55cf350fb&width=163)![image.png](https://img-blog.csdnimg.cn/img_convert/ddca321cd3b2a8380b0a7a2649e374b6.png#clientId=uae7afcd9-86a1-4&from=paste&height=148&id=ue5cb9579&margin=[object Object]&name=image.png&originHeight=434&originWidth=481&originalType=binary&ratio=1&size=20330&status=done&style=none&taskId=u24087d5f-b3e7-4814-af5a-e1eb209408d&width=163.5)
变化分支不可一世唯一的变化分支
如果是 要先进行反向旋转
![image.png](https://img-blog.csdnimg.cn/img_convert/b2d01b7e61adcb522251fcec2b2f9d13.png#clientId=uae7afcd9-86a1-4&from=paste&height=316&id=udc10a394&margin=[object Object]&name=image.png&originHeight=631&originWidth=1231&originalType=binary&ratio=1&size=64566&status=done&style=none&taskId=u6f188120-d8fc-40b2-b426-88e220ea309&width=615.5)
![image.png](https://img-blog.csdnimg.cn/img_convert/3f44a54ad92b65f5d6d30d20eca2d8e0.png#clientId=uae7afcd9-86a1-4&from=paste&height=287&id=uee98a3a4&margin=[object Object]&name=image.png&originHeight=573&originWidth=1216&originalType=binary&ratio=1&size=40370&status=done&style=none&taskId=u11aa05d7-38fb-4b96-83a1-ee77c0b0365&width=608)
二叉树的双旋(左右双旋,右左双旋)
右左双旋:当要对某个节点进行左单旋,如果变化分支是唯一的最深分支,那么要对新根进行右单旋,然后左单旋
反之左右双旋
function Node(value) {
this.value = value;
this.left = null;
this.right = null;
}
var node8 = new Node("8");
var node7 = new Node("7");
var node6 = new Node("6");
var node5 = new Node("5");
var node2 = new Node("2");
node8.left = node7;
node7.left = node6;
node6.left = node5;
node5.left = node2;
function getDeep(root) {
if (root == null) return 0;
var leftDeep = getDeep(root.left);
var rightDeep = getDeep(root.right);
return Math.max(leftDeep, rightDeep) + 1;
}
function isBalance(root) {
if (root == null) return true;
var leftDeep = getDeep(root.left);
var rightDeep = getDeep(root.right);
if (Math.abs(leftDeep - rightDeep) > 1) {//不平衡
return false;
} else {
return isBalance(root.left) && isBalance(root.right);
}
}
function leftRotate(root) {
// 找到新根
var newRoot = root.right;
// 找到变化分支
var changeTree = root.right.left;
// 当前旋转节点的右孩子为变化分支
root.right = changeTree;
// 新根的左孩子为旋转节点
newRoot.left = root;
// 返回新的根节点
return newRoot;
}
function rightRotate(root) {
// 找到新根
var newRoot = root.left;
// 找到变化分支
var changeTree = root.left.right;
// 当前旋转节点的左孩子为变化分支
root.left = changeTree;
// 新根的右孩子为旋转节点
newRoot.right = root;
// 返回新的根节点
return newRoot;
}
function change(root) {//返回平衡之后的根节点
if (isBalance(root)) return root;
if (root.left != null) root.left = change(root.left);
if (root.right != null) root.right = change(root.right);
var leftDeep = getDeep(root.left);
var rightDeep = getDeep(root.right);
if (Math.abs(leftDeep - rightDeep) < 2) {
return root;
} else if (leftDeep > rightDeep) {//不平衡,左边深,需要右旋
var changeTreeDeep = getDeep(root.left.right);
var noChangeTreeDeep = getDeep(root.left.left);
if (changeTreeDeep > noChangeTreeDeep) {
root.left = leftRotate(root.left);
}
return rightRotate(root);
} else {//不平衡,右边深,需要左旋
var changeTreeDeep = getDeep(root.right.left);
var noChangeTreeDeep = getDeep(root.right.right);
if (changeTreeDeep > noChangeTreeDeep) {
root.right = rightRotate(root.right);
}
return leftRotate(root);
}
return root;
}
function addNode(root, num) {
if (root == null) return;
if (root.value == num) return;
if (root.value < num) {//目标值比当前节点大
if (root.right == null) root.right = new Node(num);//如果右侧为空,则创建节点
else addNode(root.right, num);//如果右侧不为空,则向右侧进行递归
} else {//目标值比当前节点小
if (root.left == null) root.left = new Node(num);
else addNode(root.left, num);
}
}
function buildSearchTree(arr) {
if (arr == null || arr.length == 0) return null;
var root = new Node(arr[0]);
for (var i = 1; i < arr.length; i++) {
addNode(root, arr[i]);
}
return root;
}
var num2 = 0;
function searchByTree(root, target) {
if (root == null) return false;
num2 += 1;
if (root.value == target) return true;
if (root.value > target) return searchByTree(root.left, target);
else return searchByTree(root.right, target);
}
var arr = [];
for (var i = 0; i < 10000; i++) {
arr.push(Math.floor(Math.random() * 10000));
}
var root = buildSearchTree(arr);
// console.log(searchByTree(root, 1000));
// console.log(num2);
var newRoot = change(root);
// num2 = 0;
// console.log(searchByTree(newRoot, 1000));
// console.log(num2);
console.log(isBalance(newRoot));
// console.log(isBalance(node8));
//
// var newRoot = change(node8);
//
// console.log(isBalance(newRoot));
// console.log(newRoot);
左 左 双 旋 与 右 右 双 旋
function Node(value) {
this.value = value;
this.left = null;
this.right = null;
}
var node8 = new Node("8");
var node7 = new Node("7");
var node6 = new Node("6");
var node5 = new Node("5");
var node2 = new Node("2");
node8.left = node7;
node7.left = node6;
node6.left = node5;
node5.left = node2;
function getDeep(root) {
if (root == null) return 0;
var leftDeep = getDeep(root.left);
var rightDeep = getDeep(root.right);
return Math.max(leftDeep, rightDeep) + 1;
}
function isBalance(root) {
if (root == null) return true;
var leftDeep = getDeep(root.left);
var rightDeep = getDeep(root.right);
if (Math.abs(leftDeep - rightDeep) > 1) {//不平衡
return false;
} else {
return isBalance(root.left) && isBalance(root.right);
}
}
function leftRotate(root) {
// 找到新根
var newRoot = root.right;
// 找到变化分支
var changeTree = root.right.left;
// 当前旋转节点的右孩子为变化分支
root.right = changeTree;
// 新根的左孩子为旋转节点
newRoot.left = root;
// 返回新的根节点
return newRoot;
}
function rightRotate(root) {
// 找到新根
var newRoot = root.left;
// 找到变化分支
var changeTree = root.left.right;
// 当前旋转节点的左孩子为变化分支
root.left = changeTree;
// 新根的右孩子为旋转节点
newRoot.right = root;
// 返回新的根节点
return newRoot;
}
function change(root) {//返回平衡之后的根节点
if (isBalance(root)) return root;
if (root.left != null) root.left = change(root.left);
if (root.right != null) root.right = change(root.right);
var leftDeep = getDeep(root.left);
var rightDeep = getDeep(root.right);
if (Math.abs(leftDeep - rightDeep) < 2) {
return root;
} else if (leftDeep > rightDeep) {//不平衡,左边深,需要右旋
var changeTreeDeep = getDeep(root.left.right);
var noChangeTreeDeep = getDeep(root.left.left);
if (changeTreeDeep > noChangeTreeDeep) {
root.left = leftRotate(root.left);
}
var newRoot = rightRotate(root);
newRoot.right = change(newRoot.right);
newRoot = change(newRoot);
return newRoot;
} else {//不平衡,右边深,需要左旋
var changeTreeDeep = getDeep(root.right.left);
var noChangeTreeDeep = getDeep(root.right.right);
if (changeTreeDeep > noChangeTreeDeep) {
root.right = rightRotate(root.right);
}
var newRoot = leftRotate(root);
newRoot.left = change(newRoot.left);
newRoot = change(newRoot);
return newRoot;
}
return root;
}
function addNode(root, num) {
if (root == null) return;
if (root.value == num) return;
if (root.value < num) {//目标值比当前节点大
if (root.right == null) root.right = new Node(num);//如果右侧为空,则创建节点
else addNode(root.right, num);//如果右侧不为空,则向右侧进行递归
} else {//目标值比当前节点小
if (root.left == null) root.left = new Node(num);
else addNode(root.left, num);
}
}
function buildSearchTree(arr) {
if (arr == null || arr.length == 0) return null;
var root = new Node(arr[0]);
for (var i = 1 ; i < arr.length ; i ++) {
addNode(root, arr[i]);
}
return root;
}
var num2 = 0;
function searchByTree(root, target) {
if (root == null) return false;
num2 += 1;
if (root.value == target) return true;
if (root.value > target) return searchByTree(root.left, target);
else return searchByTree(root.right, target);
}
var arr = [];
for (var i = 0 ; i < 10000 ; i ++) {
arr.push(Math.floor(Math.random() * 10000));
}
var root = buildSearchTree(arr);
console.log(searchByTree(root, 1000));
console.log(num2);
var newRoot = change(root);
num2 = 0;
console.log(searchByTree(newRoot, 1000));
console.log(num2);
console.log(isBalance(newRoot));
// console.log(isBalance(node8));
//
// var newRoot = change(node8);
//
// console.log(isBalance(newRoot));
// console.log(newRoot);
树的深度优先搜索
function Node(value) {
this.value = value;
this.childs = [];
}
var a = new Node("a");
var b = new Node("b");
var c = new Node("c");
var d = new Node("d");
var e = new Node("e");
var f = new Node("f");
a.childs.push(c);
a.childs.push(f);
a.childs.push(b);
b.childs.push(d);
b.childs.push(e);
function deepSearch(root, target) {
if (root == null) return false;
if (root.value == target) return true;
var result = false;
for (var i = 0 ; i < root.childs.length ; i ++) {
result |= deepSearch(root.childs[i], target);
}
return result ? true : false;
}
console.log(deepSearch(a, "n"))
树的广度优先搜索
function Node(value) {
this.value = value;
this.childs = [];
}
var a = new Node("a");
var b = new Node("b");
var c = new Node("c");
var d = new Node("d");
var e = new Node("e");
var f = new Node("f");
a.childs.push(c);
a.childs.push(f);
a.childs.push(b);
b.childs.push(d);
b.childs.push(e);
function bfs(roots, target) {
if (roots == null || roots.length == 0) return false;
var childs = [];
for (var i = 0 ; i < roots.length ; i ++) {
if (roots[i].value == target) {
return true;
} else {
childs = childs.concat(roots[i].childs);
}
}
return bfs(childs, target);
}
console.log(bfs([a], "n"));
图的深度优先
不要形成环
function Node(value) {
this.value = value;
this.neighbor = [];
}
var a = new Node("a");
var b = new Node("b");
var c = new Node("c");
var d = new Node("d");
var e = new Node("e");
a.neighbor.push(b);
a.neighbor.push(c);
b.neighbor.push(a);
b.neighbor.push(c);
b.neighbor.push(d);
c.neighbor.push(a);
c.neighbor.push(b);
c.neighbor.push(d);
d.neighbor.push(b);
d.neighbor.push(c);
d.neighbor.push(e);
e.neighbor.push(d);
function deepSearch(node, target, path) {
if (node == null) return false;
if (path.indexOf(node) > -1) return false;
if (node.value == target) return true;
path.push(node);
var result = false;
for (var i = 0 ; i < node.neighbor.length ; i ++) {
result |= deepSearch(node.neighbor[i], target, path);//一真为真
}
return result ? true : false;
}
console.log(deepSearch(b, "d", []));
图的广度优先
function Node(value) {
this.value = value;
this.neighbor = [];
}
var a = new Node("a");
var b = new Node("b");
var c = new Node("c");
var d = new Node("d");
var e = new Node("e");
a.neighbor.push(b);
a.neighbor.push(c);
b.neighbor.push(a);
b.neighbor.push(c);
b.neighbor.push(d);
c.neighbor.push(a);
c.neighbor.push(b);
c.neighbor.push(d);
d.neighbor.push(b);
d.neighbor.push(c);
d.neighbor.push(e);
e.neighbor.push(d);
function bfs(nodes, target, path) {
if (nodes == null || nodes.length == 0) return false;
var nextNodes = [];
for (var i = 0 ; i < nodes.length ; i ++) {
if (path.indexOf(nodes[i]) > -1) continue;
path.push(nodes[i]);
if (nodes[i].value == target) return true;
else nextNodes = nextNodes.concat(nodes[i].neighbor);
}
return bfs(nextNodes, target, path);
}
console.log(bfs([c], "n", []));