简体   繁体   中英

In a tree with arbitrary number of children, find whether a node is in the left half subtrees or right half subtrees of a given node

Question: To find whether a node is in the left half subtrees or the right half subtrees of a node root .


Meaning of left half and right half : Suppose a node root has n child and each of which has subtrees.

A node is said to be in the left half subtrees of root , if it is a node numbered [1..(Math.floor(n/2))] from left to right or it is a node in one of their subtrees, else it is in the right half subtrees of root [(Math.floor(n/2) + 1)..n] .

All the nodes in the left half get key values less than root and all the nodes in the right half get key values greater than root.


Idea : Preprocessing

Do an inorder traversal of the tree and assign key (Whole numbers) to each node in adjacencyLists.node . Then on query, compare key values to determine whether a node is in the left half subtrees or right half subtrees:

Pseudo code:

QUERY(root, queryNode)
  if (queryNode.key < root.key) {
    print "queryNode is in left half of root"
  } else {
    print "queryNode is in the right half of root"
  }

Implementation:

 var adjacencyLists = { root: 'A', nodes: { A: { id: 'A', connectedNodes: ['B', 'C'] }, B: { id: 'B', connectedNodes: ['D', 'E'] }, C: { id: 'C', connectedNodes: ['F', 'G', 'H', 'Q', 'R'] }, D: { id: 'D', connectedNodes: [] }, E: { id: 'E', connectedNodes: ['K'] }, F: { id: 'F', connectedNodes: ['I'] }, G: { id: 'G', connectedNodes: ['J', 'L', 'N', 'P'] }, H: { id: 'H', connectedNodes: ['M', 'O'] }, K: { id: 'K', connectedNodes: [] }, I: { id: 'I', connectedNodes: [] }, J: { id: 'J', connectedNodes: [] }, L: { id: 'L', connectedNodes: [] }, M: { id: 'M', connectedNodes: [] }, N: { id: 'N', connectedNodes: [] }, O: { id: 'O', connectedNodes: [] }, P: { id: 'P', connectedNodes: [] }, Q: { id: 'Q', connectedNodes: [] }, R: { id: 'R', connectedNodes: [] }, } } var keyLookup = {}; var count = 0; function inorderTraversalNumberingOfNodes(cur) { if (adjacencyLists.nodes[cur].connectedNodes.length) { // recurse left half subtrees for (let i = 0; i < Math.ceil(adjacencyLists.nodes[cur].connectedNodes.length / 2); i++) { inorderTraversalNumberingOfNodes(adjacencyLists.nodes[cur].connectedNodes[i]); } // recurse right half subtrees for (let i = Math.ceil(adjacencyLists.nodes[cur].connectedNodes.length / 2); i < adjacencyLists.nodes[cur].connectedNodes.length; i++) { inorderTraversalNumberingOfNodes(adjacencyLists.nodes[cur].connectedNodes[i]); } count++; keyLookup[cur] = { key: count }; } else { count++; keyLookup[cur] = {key : count }; } } inorderTraversalNumberingOfNodes(adjacencyLists.root); console.log(keyLookup) // query to determine whether a node is in the left half or right half of root function query(rootNodeId, queryNodeId) { if (keyLookup[queryNodeId].key < keyLookup[rootNodeId].key) { console.log(`query node ${queryNodeId} is in the left half of root node ${rootNodeId}`); } else { console.log(`query node ${queryNodeId} is in the right half of root node ${rootNodeId}`); } } query('A', 'D'); query('M', 'C');


Expected key values of nodes : An inorder traversal of the adjacency list should assign following key to nodes:

{
  "D": {
    "key": 1
  },
  "K": {
    "key": 3
  },
  "E": {
    "key": 4
  },
  "B": {
    "key": 2
  },
  "I": {
    "key": 6
  },
  "F": {
    "key": 7
  },
  "J": {
    "key": 8
  },
  "L": {
    "key": 9
  },
  "N": {
    "key": 11
  },
  "P": {
    "key": 12
  },
  "G": {
    "key": 10
  },
  "M": {
    "key": 14
  },
  "O": {
    "key": 16
  },
  "H": {
    "key": 15
  },
  "Q": {
    "key": 17
  },
  "R": {
    "key": 18
  },
  "C": {
    "key": 13
  },
  "A": {
    "key": 5
  }
}

Now, on QUERY(A, D) , the output should be queryNode is in left half of root , since 1 < 5 .

I don't get the expected answer since I am unable to assign correct key to nodes.

You could get the order first and then take the index value for getting the side.

 var adjacencyLists = { root: 'A', nodes: { A: { id: 'A', connectedNodes: ['B', 'C'] }, B: { id: 'B', connectedNodes: ['D', 'E'] }, C: { id: 'C', connectedNodes: ['F', 'G', 'H', 'Q', 'R'] }, D: { id: 'D', connectedNodes: [] }, E: { id: 'E', connectedNodes: ['K'] }, F: { id: 'F', connectedNodes: ['I'] }, G: { id: 'G', connectedNodes: ['J', 'L', 'N', 'P'] }, H: { id: 'H', connectedNodes: ['M', 'O'] }, K: { id: 'K', connectedNodes: [] }, I: { id: 'I', connectedNodes: [] }, J: { id: 'J', connectedNodes: [] }, L: { id: 'L', connectedNodes: [] }, M: { id: 'M', connectedNodes: [] }, N: { id: 'N', connectedNodes: [] }, O: { id: 'O', connectedNodes: [] }, P: { id: 'P', connectedNodes: [] }, Q: { id: 'Q', connectedNodes: [] }, R: { id: 'R', connectedNodes: [] } } }, index = 0, getOrder = parent => value => { if (!adjacencyLists.nodes[value].connectedNodes.length) { adjacencyLists.nodes[value].index = adjacencyLists.nodes[value].index || ++index; } adjacencyLists.nodes[value].connectedNodes.forEach(getOrder(value)); adjacencyLists.nodes[parent].index = adjacencyLists.nodes[parent].index || ++index; }, query = (a, b) => a === b ? 'middle' : adjacencyLists.nodes[a].index < adjacencyLists.nodes[b].index ? 'left' : 'right'; getOrder('A')('A'); console.log(query('A', 'D')); // or vice versa ...? console.log(adjacencyLists);
 .as-console-wrapper { max-height: 100% !important; top: 0; }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM