Reputation: 322
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.
Upvotes: 1
Views: 171
Reputation: 386620
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; }
Upvotes: 1