爲了你們方便學習和講解紅黑樹,特製做這個在線生成紅黑樹。並且每次刪除和新增破壞了紅黑樹特性致使變形,還會羅列出變形步驟。html
學數據結構推薦你們查看 skywang12345(若是天空不死)的博客 http://www.cnblogs.com/skywang12345/p/3603935.htmlnode
在線演示地址:http://sandbox.runjs.cn/show/2nngvn8wcanvas
源碼:數據結構
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>在線生成紅黑樹(含變形步驟)</title> </head> <body> <div> <ul> <li>增長節點</li> <li>方式一:<input type="button" value="隨機增長一個節點" title="隨機增長一個節點" onclick="AddRandom()" /></li> <li>方式二:<input id="numbertext" title="" placeholder="請用,(單字節)分割數字,0-999之間的數字" value="" /><input type="button" value="一個一個節點增長" title="增長一個節點" onclick="AddOneNumber()" /></li> <li></li> <li>刪除節點</li> <li><input id="deleteNumberText" type="text" placeholder="請輸入須要刪除的節點" /><input type="button" value="刪除" onclick="DeleteNumber()" /> </li> <li></li> <li>參考: http://www.cnblogs.com/skywang12345/p/3603935.html </li> </ul> </div> <form> <fieldset> <legend>紅黑樹</legend> <div id="currentView"></div> </fieldset> </form> <form id="stepView"></form> <!--個人博客: http://www.cnblogs.com/bbvi/ --> <script> var NodeColor = { Black: "black", Red: "red" }; var RBNode = function (_date, _paret, _color) { this.Data = _date; this.Parent = _paret; this.Color = _color; this.LeftNode = null; this.RightNode = null; } var RedBlackBinaryTree = function () { this.RootNode = null;//根節點 this.Insert = function (insertValue) { if (this.RootNode == null) { this.RootNode = new RBNode(insertValue, null, NodeColor.Black); } else { var newNode = insert.call(this, insertValue); insertFixUp.call(this, newNode); } } function insert(key) { ClearStepView();//清空分解步驟 var node = this.RootNode; var newNode = new RBNode(key, null, NodeColor.Red); while (true) { if (key > node.Data) { if (node.RightNode == null) { newNode.Parent = node; node.RightNode = newNode; break; } node = node.RightNode; } else if (key < node.Data) { if (node.LeftNode == null) { newNode.Parent = node; node.LeftNode = newNode; break; } node = node.LeftNode; } else { break; } } return newNode; } function insertFixUp(node) { var parentNode = node.Parent; if (parentNode != null && NodeColor.Red == parentNode.Color) { var gprentNode = parentNode.Parent; if (parentNode == gprentNode.LeftNode) { var uncleNode = gprentNode.RightNode; if (uncleNode != null && NodeColor.Red == uncleNode.Color) { CreateStepView(this.RootNode, "insertCaseA1", node.Data);//記錄分解步驟 parentNode.Color = NodeColor.Black; uncleNode.Color = NodeColor.Black; gprentNode.Color = NodeColor.Red; CreateStepView(this.RootNode, "insertSolutionA1");//記錄分解步驟 insertFixUp.call(this, gprentNode); } else { if (parentNode.RightNode == node) { CreateStepView(this.RootNode, "insertCaseB1", node.Data);//記錄分解步驟 leftRotation.call(this, parentNode); CreateStepView(this.RootNode, "insertSolutionB1");//記錄分解步驟 insertFixUp.call(this, parentNode); } else if (parentNode.LeftNode == node) { CreateStepView(this.RootNode, "insertCase3", node.Data);//記錄分解步驟 parentNode.Color = NodeColor.Black; gprentNode.Color = NodeColor.Red; rightRotation.call(this, gprentNode); CreateStepView(this.RootNode, "insertSolution3");//記錄分解步驟 } } } else { var uncleNode = gprentNode.LeftNode; if (uncleNode != null && NodeColor.Red == uncleNode.Color) { CreateStepView(this.RootNode, "insertCaseA1", node.Data);//記錄分解步驟 parentNode.Color = NodeColor.Black; uncleNode.Color = NodeColor.Black; gprentNode.Color = NodeColor.Red; CreateStepView(this.RootNode, "insertSolutionA1");//記錄分解步驟 insertFixUp.call(this, gprentNode); } else { if (parentNode.LeftNode == node) { CreateStepView(this.RootNode, "insertCase4", node.Data);//記錄分解步驟 rightRotation.call(this, parentNode); CreateStepView(this.RootNode, "insertSolution4");//記錄分解步驟 insertFixUp.call(this, parentNode); } else if (parentNode.RightNode == node) { CreateStepView(this.RootNode, "insertCase5", node.Data);//記錄分解步驟 parentNode.Color = NodeColor.Black; gprentNode.Color = NodeColor.Red; leftRotation.call(this, gprentNode); CreateStepView(this.RootNode, "insertSolution5");//記錄分解步驟 } } } } this.RootNode.Color = NodeColor.Black; } function leftRotation(node) { var temp = node.RightNode; node.RightNode = temp.LeftNode; if (temp.LeftNode != null) { temp.LeftNode.Parent = node; } temp.Parent = node.Parent; if (node.Parent == null) { this.RootNode = temp; } else { if (node.Parent.LeftNode == node) { node.Parent.LeftNode = temp; } else { node.Parent.RightNode = temp; } } temp.LeftNode = node; node.Parent = temp; } function rightRotation(node) { var temp = node.LeftNode; node.LeftNode = temp.RightNode; if (temp.RightNode != null) { temp.RightNode.Parent = node; } temp.Parent = node.Parent; if (node.Parent == null) { this.RootNode = temp; } else { if (node == node.Parent.RightNode) { node.Parent.RightNode = temp; } else { node.Parent.LeftNode = temp; } } temp.RightNode = node; node.Parent = temp; } this.Remove = function (key) { var node = search.call(this, this.RootNode, key); if (node == null) { return; } else { remove.call(this, node); } } function remove(node) { ClearStepView();//清空分解步驟 var child, parent, nodeColor; if (node.LeftNode != null && node.RightNode != null) { CreateStepView(this.RootNode, "deleteCase8", node.Data);//記錄分解步驟 var tempNode = findMin(node.RightNode); if (node.Parent == null) { this.RootNode = tempNode; } else { if (node.Parent.LeftNode == node) { node.Parent.LeftNode = tempNode; } else { node.Parent.RightNode = tempNode; } } child = tempNode.RightNode; parent = tempNode.Parent; nodeColor = tempNode.Color; if (parent.Data == node.Data) { parent = tempNode; } else { if (child != null) { child.Parent = parent; } parent.LeftNode = child; tempNode.RightNode = node.RightNode; node.RightNode.Parent = tempNode; } tempNode.Parent = node.Parent; tempNode.Color = node.Color; tempNode.LeftNode = node.LeftNode node.LeftNode.Parent = tempNode; CreateStepView(this.RootNode, "deleteSolution8");//記錄分解步驟 if (nodeColor == NodeColor.Black) { removeFixUp.call(this, child, parent); } } else { CreateStepView(this.RootNode, "deleteCase9", node.Data);//記錄分解步驟 if (node.LeftNode != null) { child = node.LeftNode; } else { child = node.RightNode; } parent = node.Parent; nodeColor = node.Color; if (child != null) { child.Parent = parent; } if (parent != null) { if (parent.LeftNode != null && parent.LeftNode.Data == node.Data) { parent.LeftNode = child; } else { parent.RightNode = child; } } else { this.RootNode = child; } CreateStepView(this.RootNode, "deleteSolution9");//記錄分解步驟 if (nodeColor == NodeColor.Black) { removeFixUp.call(this, child, parent) } } node = null; } function removeFixUp(node, parentNode) { var otherNode; while ((node == null || node.Color == NodeColor.Black) && (node != this.RootNode)) { if (parentNode.LeftNode == node) { otherNode = parentNode.RightNode; if (otherNode.Color == NodeColor.Red) { CreateStepView(this.RootNode, "deleteCase1");//記錄分解步驟 otherNode.Color = NodeColor.Black; parentNode.Color = NodeColor.Red; leftRotation.call(this, parentNode); otherNode = parentNode.RightNode; CreateStepView(this.RootNode, "deleteSolution1");//記錄分解步驟 } if ((otherNode.LeftNode == null || otherNode.LeftNode.Color == NodeColor.Black) && (otherNode.RightNode == null || otherNode.RightNode.Color == NodeColor.Black)) { CreateStepView(this.RootNode, "deleteCase3");//記錄分解步驟 otherNode.Color = NodeColor.Red; node = parentNode; parentNode = node.Parent; CreateStepView(this.RootNode, "deleteSolution3");//記錄分解步驟 } else { if (otherNode.RightNode == null || otherNode.RightNode.Color == NodeColor.Black) { CreateStepView(this.RootNode, "deleteCase4");//記錄分解步驟 otherNode.LeftNode.Color == NodeColor.Black; otherNode.Color = NodeColor.Red; rightRotation.call(this, otherNode); otherNode = parentNode.RightNode; CreateStepView(this.RootNode, "deleteSolution4");//記錄分解步驟 } CreateStepView(this.RootNode, "deleteCase6");//記錄分解步驟 otherNode.Color = parentNode.Color; parentNode.Color = NodeColor.Black; otherNode.RightNode.Color = NodeColor.Black; leftRotation.call(this, parentNode); node = this.RootNode; CreateStepView(this.RootNode, "deleteSolution6");//記錄分解步驟 break; } } else { otherNode = parentNode.LeftNode; if (otherNode.Color == NodeColor.Red) { CreateStepView(this.RootNode, "deleteCase2");//記錄分解步驟 otherNode.Color = NodeColor.Black; parentNode.Color = NodeColor.Red; rightRotation.call(this, parentNode); otherNode = parentNode.LeftNode; CreateStepView(this.RootNode, "deleteSolution2");//記錄分解步驟 } if ((otherNode.LeftNode == null || otherNode.LeftNode.Color == NodeColor.Black) && (otherNode.RightNode == null || otherNode.RightNode.Color == NodeColor.Black)) { CreateStepView(this.RootNode, "deleteCase3");//記錄分解步驟 otherNode.Color = NodeColor.Red; node = parentNode; parentNode = node.parent; CreateStepView(this.RootNode, "deleteSolution3");//記錄分解步驟 } else { if (otherNode.LeftNode == null || otherNode.LeftNode.Color == NodeColor.Black) { CreateStepView(this.RootNode, "deleteCase5");//記錄分解步驟 otherNode.RightNode.Color = NodeColor.Black; otherNode.Color = NodeColor.Red; leftRotation.call(this, otherNode); otherNode = parentNode.LeftNode; CreateStepView(this.RootNode, "deleteSolution5");//記錄分解步驟 } CreateStepView(this.RootNode, "deleteCase7");//記錄分解步驟 otherNode.Color = parentNode.Color; parentNode.Color = NodeColor.Black; otherNode.LeftNode.Color = NodeColor.Black; rightRotation.call(this, parentNode); node = this.RootNode; CreateStepView(this.RootNode, "deleteSolution7");//記錄分解步驟 break; } } } if (node != null) { node.Color = NodeColor.Black; } } this.Search = function (key) { return search.call(this, this.RootNode, key); } function search(node, key) { if (node == null) { return null; } if (node.Data > key) { return search(node.LeftNode, key); } else if (node.Data < key) { return search(node.RightNode, key); } else { return node; } } this.FindMin = function () { return findMin(this.RootNode); } function findMin(node) { if (node.LeftNode == null) { return node; } return findMin(node.LeftNode); } this.FindMax = function () { return findMax(this.RootNode) } function findMax(node) { if (node.RightNode == null) { return node; } return findMax(node.RightNode); } this.SearchRange = function (minKey, maxKey) { return searchRange(minKey, maxKey, this.RootNode, []); } function searchRange(minKey, maxKey, node, nodeList) { if (node == null) { return nodeList; } if (node.Data > minKey) { searchRange(minKey, maxKey, node.LeftNode, nodeList); } if (node.Data >= minKey && node.Data < maxKey) { nodeList.push(node.Data); } if (node.Data < maxKey) { searchRange(minKey, maxKey, node.RightNode, nodeList); } return nodeList; } this.LevelOrder = function (action) { levelOrder(this.RootNode, action); } function levelOrder(node, action) { var stack = []; stack.push(node); while (stack.length > 0) { var temp = stack.pop(); action(temp); if (temp.LeftNode != null) { stack.push(temp.LeftNode); } if (temp.RightNode != null) { stack.push(temp.RightNode); } } } this.PreOrder = function (action) { treeOrder(this.RootNode, action, null, null); } this.InOrder = function (action) { treeOrder(this.RootNode, null, action, null); } this.PostOrder = function (action) { treeOrder(this.RootNode, null, null, action); } function treeOrder(node, preOrderAction, inOrderAction, postOrderAction) { if (preOrderAction) { preOrderAction(node); } if (node.LeftNode != null) { treeOrder(node.LeftNode, preOrderAction, inOrderAction, postOrderAction); } if (inOrderAction) { inOrderAction(node); } if (node.RightNode != null) { treeOrder(node.RightNode, preOrderAction, inOrderAction, postOrderAction); } if (postOrderAction) { postOrderAction(node); } } } </script> <script> var height = 50;//節點之間的高 var width = 15;//節點之間的寬 var tops = 40;//根節點離頂部的距離 var foot = 40;//樹離底部距離 var spacing = 30;//樹分別離兩邊的間距 var tree = new RedBlackBinaryTree(); function AddOneNumber() { var numbertext = document.getElementById("numbertext").value; var oneNums = numbertext.match(/[1-9][0-9]{0,2}\,?/); document.getElementById("numbertext").value = numbertext.replace(/[1-9][0-9]{0,2}\,?/, ""); var num = (oneNums + "").match(/[1-9][0-9]{0,2}/); if (!!num) { AddNumber(parseInt(num)); } } function AddRandom() { AddNumber(Math.floor(Math.random() * (1000))); } function AddAllNumber() { while (true) { AddOneNumber(); var numbertext = document.getElementById("numbertext").value; if (!/[1-9][0-9]{0,2}/.test(numbertext)) { break; } } } function AddNumber(number) { tree.Insert(number); RenewView(tree); } function DeleteNumber() { var deleteNumberText = document.getElementById("deleteNumberText").value; if (!deleteNumberText.match(/^[1-9][0-9]{0,2}$/)) { alert("請正確輸入1-999的整數"); return false; } var number = parseInt(deleteNumberText); var isExist = tree.Search(number); if (!isExist) { alert("不存在此節點"); return false; } tree.Remove(number); document.getElementById("deleteNumberText").value = ''; RenewView(tree); } function RenewView(_tree) { var currentView = document.getElementById("currentView"); currentView.innerHTML = ''; CreateTreeView(_tree.RootNode, currentView); } function CreateTreeView(rootNode, hostDocument) { var size = SetCanvasWidthHeight(rootNode); var canvas = document.createElement("canvas"); canvas.style.backgroundColor = "antiquewhite"; canvas.style.display = "block"; canvas.height = size.height; canvas.width = size.width; var context = canvas.getContext("2d"); hostDocument.appendChild(canvas); SetPoint(rootNode); PreOrder(rootNode, SetPreOrder, context, canvas.width); } function PreOrder(node, action, context, canvasWidth) { action(node, context, canvasWidth); if (node.LeftNode != null) { PreOrder(node.LeftNode, action, context, canvasWidth); } if (node.RightNode != null) { PreOrder(node.RightNode, action, context, canvasWidth); } } function SetCanvasWidthHeight(rootNode) { var level = Level(rootNode); return { height: height * level + tops + foot, width: Math.pow(2, level + 1) * width + spacing * 2 }; } function SetPreOrder(node, context, canvasWidth) { var container = drawArc( context, node.Data, canvasWidth / 2 + width * node.nodePoint, (node.nodeLevel * height + parseInt(tops)), node.Color); if (node.Parent != null) { var line = linkNode( context, (canvasWidth / 2 + width * node.Parent.nodePoint), (node.Parent.nodeLevel * height + parseInt(tops)), (node.Data, canvasWidth / 2 + width * node.nodePoint), (node.nodeLevel * height + parseInt(tops))); } } //生產節點 function drawArc(context, number, x, y, color) { //圓 context.beginPath(); context.fillStyle = color; context.arc(x, y, 15, (Math.PI / 180) * 0, (Math.PI / 180) * 360, false); context.fill(); context.closePath(); //數字 var textX = x; var textY = y + 5; if (number < 10) { textX -= 5; } else if (number > 9 && number < 100) { textX -= 8; } else { textX -= 12; } context.fillStyle = "white"; context.font = "bold 15px Arial"; context.fillText(number + "", textX, textY); } //連接節點 function linkNode(context, fatherNodeX, fatherNodeY, childrenNodeX, childrenNodeY) { drawLine(context, fatherNodeX, fatherNodeY + 15, childrenNodeX, childrenNodeY - 15); } //生產線 function drawLine(context, x, y, toX, toY) { context.moveTo(x, y); context.lineTo(x, y); context.lineTo(toX, toY); context.stroke(); } var maxLevel; var level; function Level(rootNode) { maxLevel = 0; level = 0; return levels(rootNode); } function levels(node) { if (node.LeftNode != null) { level++; levels(node.LeftNode); } maxLevel = Math.max(maxLevel, level); if (node.RightNode != null) { level++; levels(node.RightNode); } level--; return maxLevel; } function SetPoint(rootNode) { var thisMaxLevel = Level(rootNode); var childQuanty = Math.pow(2, thisMaxLevel); rootNode.nodeLevel = 0; rootNode.nodePoint = 0; if (rootNode.LeftNode != null) { setPointsLeft(rootNode.LeftNode, -1 * childQuanty / 2, 0, thisMaxLevel - 1); } if (rootNode.RightNode != null) { setPointsRight(rootNode.RightNode, childQuanty / 2, 0, thisMaxLevel - 1); } } function setPointsLeft(node, point, levels, thisMaxLevel) { ++levels; node.nodeLevel = levels; node.nodePoint = point; if (node.LeftNode != null) { setPointsLeft(node.LeftNode, point - Math.pow(2, thisMaxLevel - levels), levels, thisMaxLevel); } if (node.RightNode != null) { setPointsLeft(node.RightNode, point + Math.pow(2, thisMaxLevel - levels), levels, thisMaxLevel); } } function setPointsRight(node, point, levels, thisMaxLevel) { ++levels; node.nodeLevel = levels; node.nodePoint = point; if (node.LeftNode != null) { setPointsRight(node.LeftNode, point - Math.pow(2, thisMaxLevel - levels), levels, thisMaxLevel); } if (node.RightNode != null) { setPointsRight(node.RightNode, point + Math.pow(2, thisMaxLevel - levels), levels, thisMaxLevel); } } var stepRemark = { "insertCaseA1": { "title": "插入節點狀況A1", "remark": [ "當前節點的父節點是紅色,且當前節點的祖父節點的另外一個子節點(叔叔節點)也是紅色" ] }, "insertSolutionA1": { "title": "插入節點狀況A1的解決方案", "remark": [ "(01) 將「父節點」設爲黑色", "(02) 將「叔叔節點」設爲黑色", "(03) 將「祖父節點」設爲「紅色", "(04) 將「祖父節點」設爲「當前節點」(紅色節點);即,以後繼續對「當前節點」進行操做" ] }, "insertCaseB1": { "title": "插入節點狀況2", "remark": [ "當前節點的父節點是紅色,叔叔節點是黑色,且當前節點是其父節點的右孩子" ] }, "insertSolutionB1": { "title": "插入節點狀況2的解決方案", "remark": [ "(01) 將「父節點」做爲「新的當前節點」", "(02) 以「新的當前節點」爲支點進行左旋", ] }, "insertCase3": { "title": "插入節點狀況3", "remark": [ "當前節點的父節點是紅色,叔叔節點是黑色,且當前節點是其父節點的左孩子" ] }, "insertSolution3": { "title": "插入節點狀況3的解決方案", "remark": [ "(01) 將「父節點」設爲「黑色」", "(02) 將「祖父節點」設爲「紅色」", "(03) 以「祖父節點」爲支點進行右旋" ] }, "insertCase4": { "title": "插入節點狀況4", "remark": [ "當前節點的父節點是紅色,叔叔節點是黑色,且當前節點是其父節點的左孩子" ] }, "insertSolution4": { "title": "插入節點狀況4的解決方案", "remark": [ "(01) 將「父節點」做爲「新的當前節點」", "(02) 以「新的當前節點」爲支點進行右旋", ] }, "insertCase5": { "title": "插入節點狀況5", "remark": [ "當前節點的父節點是紅色,叔叔節點是黑色,且當前節點是其父節點的右孩子" ] }, "insertSolution5": { "title": "插入節點狀況5的解決方案", "remark": [ "(01) 將「父節點」設爲「黑色」", "(02) 將「祖父節點」設爲「紅色」", "(03) 以「祖父節點」爲支點進行左旋" ] }, "deleteCase1": { "title": "刪除節點狀況1", "remark": [ "被刪節點是「黑+黑」節點,被刪除的節點是左節點,被刪節點的兄弟節點是紅色。(此時被刪節點的父節點和x的兄弟節點的子節點都是黑節點)。" ] }, "deleteSolution1": { "title": "刪除節點狀況1解決方案", "remark": [ "(01) 將x的兄弟節點設爲「黑色」。", "(02) 將x的父節點設爲「紅色」。", "(03) 對x的父節點進行左旋。", "(04) 左旋後,從新設置x的兄弟節點。" ] }, "deleteCase2": { "title": "刪除節點狀況2", "remark": [ "被刪節點是「黑+黑」節點,被刪除的節點是右節點,被刪節點的兄弟節點是紅色。(此時被刪節點的父節點和x的兄弟節點的子節點都是黑節點)。" ] }, "deleteSolution2": { "title": "刪除節點狀況2解決方案", "remark": [ "(01) 將被刪節點的兄弟節點設爲「黑色」。", "(02) 將被刪節點的父節點設爲「紅色」。", "(03) 對被刪節點的父節點進行右旋。", "(04) 右旋後,從新設置x的兄弟節點。" ] }, "deleteCase3": { "title": "刪除節點狀況3", "remark": [ "被刪節點是「黑+黑」節點,被刪節點的兄弟節點是黑色,被刪節點的兄弟節點的兩個孩子都是黑色。" ] }, "deleteSolution3": { "title": "刪除節點狀況3解決方案", "remark": [ "(01) 將被刪節點的兄弟節點設爲「紅色」。", "(02) 設置「被刪節點的父節點」爲「新的被刪節點節點」。" ] }, "deleteCase4": { "title": "刪除節點狀況4", "remark": [ "將被刪節點是「黑+黑」節點,被刪節點的兄弟節點是黑色;將被刪節點的兄弟節點的左孩子是紅色,右孩子是黑色的。" ] }, "deleteSolution4": { "title": "刪除節點狀況4解決方案", "remark": [ "(01) 將被刪節點兄弟節點的左孩子設爲「黑色」。", "(02) 將被刪節點兄弟節點設爲「紅色」。", "(03) 對被刪節點的兄弟節點進行右旋。", "(04) 右旋後,從新設置被刪節點的兄弟節點。", ] }, "deleteCase5": { "title": "刪除節點狀況5", "remark": [ "被刪節點是「黑+黑」節點,被刪節點的兄弟節點是黑色;被刪節點的兄弟節點的左孩子是黑色,右孩子是紅色的。" ] }, "deleteSolution5": { "title": "刪除節點狀況5解決方案", "remark": [ "(01) 將被刪節點兄弟節點的右孩子設爲「黑色」。", "(02) 將被刪節點兄弟節點設爲「紅色」。", "(03) 對被刪節點的兄弟節點進行左旋。", "(04) 左旋後,從新設置被刪節點的兄弟節點。", ] }, "deleteCase6": { "title": "刪除節點狀況6", "remark": [ "被刪節點是「黑+黑」節點,被刪節點的兄弟節點是黑色;被刪節點的兄弟節點的右孩子是紅色的,被刪節點的兄弟節點的左孩子任意顏色。" ] }, "deleteSolution6": { "title": "刪除節點狀況6解決方案", "remark": [ "(01) 將被刪節點父節點顏色 賦值給 被刪節點的兄弟節點。", "(02) 將被刪節點父節點設爲「黑色」。", "(03) 將被刪節點兄弟節點的右子節點設爲「黑色」。", "(04) 對被刪節點的父節點進行左旋。", "(05) 設置「被刪節點」爲「根節點」。" ] }, "deleteCase7": { "title": "刪除節點狀況7", "remark": [ "被刪節點是「黑+黑」節點,被刪節點的兄弟節點是黑色;被刪節點的兄弟節點的左孩子是紅色的,被刪節點的兄弟節點的右孩子任意顏色。" ] }, "deleteSolution7": { "title": "刪除節點狀況7解決方案", "remark": [ "(01) 將被刪節點父節點顏色 賦值給 被刪節點的兄弟節點。", "(02) 將被刪節點父節點設爲「黑色」。", "(03) 將被刪節點兄弟節點的左子節設爲「黑色」。", "(04) 對被刪節點的父節點進行右旋。", "(05) 設置「被刪節點」爲「根節點」。" ] }, "deleteCase8": { "title": "刪除節點狀況8", "remark": [ "被刪節點有兩個子節點" ] }, "deleteSolution8": { "title": "刪除節點狀況8解決方案", "remark": [ "(01) 將被刪節點右節點的子孫節點中找出小的節點,替換被刪節點。", ] }, "deleteCase9": { "title": "刪除節點狀況9", "remark": [ "被刪節點只有一個子節點或無子節點" ] }, "deleteSolution9": { "title": "刪除節點狀況9解決方案", "remark": [ "(01) 將惟一的子節點替換被刪節點。", ] } }; function ClearStepView() { var stepView = document.getElementById("stepView"); stepView.innerHTML = ''; } function CreateStepView(_tree, step, currentNumber) { var fieldset = document.createElement("fieldset"); var legend = document.createElement("legend"); var ul = document.createElement("ul"); var canvas = document.createElement("canvas"); legend.innerHTML = stepRemark[step].title; if (!!currentNumber) { var li = document.createElement("li"); li.innerHTML = "當前節點:" + currentNumber; ul.appendChild(li); } for (var i = 0; i < stepRemark[step].remark.length; i++) { var li = document.createElement("li"); li.innerHTML = stepRemark[step].remark[i]; ul.appendChild(li); } fieldset.appendChild(legend); fieldset.appendChild(ul); fieldset.appendChild(canvas); var stepView = document.getElementById("stepView"); stepView.appendChild(fieldset); CreateStepTreeView(_tree, canvas); } function CreateStepTreeView(rootNode, canvas) { var size = SetCanvasWidthHeight(rootNode); canvas.style.backgroundColor = "antiquewhite"; canvas.style.display = "block"; canvas.height = size.height; canvas.width = size.width; var context = canvas.getContext("2d"); SetPoint(rootNode); PreOrder(rootNode, SetPreOrder, context, canvas.width); } </script> </body> </html>