求满二叉树两个节点之间的最短距离
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace FirstSolver
{
internal class Program
{
static void Main(string[] args)
{
BinaryTreeNode<int> root1 = FullBinaryTree.CreateTree(1, 4);
Console.WriteLine(FullBinaryTree.PrintTree(root1));
Console.WriteLine();
BinaryTreeNode<int> root2 = FullBinaryTree.CreateTree(101, 4);
Console.WriteLine(FullBinaryTree.PrintTree(root2));
Console.WriteLine();
BinaryTreeNode<int> root3 = FullBinaryTree.CreateTree(201, 4);
Console.WriteLine(FullBinaryTree.PrintTree(root3));
Console.WriteLine();
root1.ParentNode = root2;
root2.ParentNode = root3;
root3.ParentNode = root1;
BinaryTreeNode<int> nodeA = FullBinaryTree.FindNode(root1, 5);
BinaryTreeNode<int> nodeB = FullBinaryTree.FindNode(root1, 7);
Console.WriteLine($"[A({nodeA.Value})]->[B({nodeB.Value})]");
Stack<BinaryTreeNode<int>> path = FullBinaryTree.FindPath(nodeA, nodeB);
Console.WriteLine(FullBinaryTree.PrintPath(path));
Console.WriteLine(FullBinaryTree.PrintPath(FullBinaryTree.QuickFindPath(nodeA, nodeB)));
Console.WriteLine();
nodeB = FullBinaryTree.FindNode(root2, 107);
Console.WriteLine($"[A({nodeA.Value})]->[B({nodeB.Value})]");
path = FullBinaryTree.FindPath(nodeA, nodeB);
Console.WriteLine(FullBinaryTree.PrintPath(path));
Console.WriteLine(FullBinaryTree.PrintPath(FullBinaryTree.QuickFindPath(nodeA, nodeB)));
Console.WriteLine();
nodeB = FullBinaryTree.FindNode(root3, 207);
Console.WriteLine($"[A({nodeA.Value})]->[B({nodeB.Value})]");
path = FullBinaryTree.FindPath(nodeA, nodeB);
Console.WriteLine(FullBinaryTree.PrintPath(path));
Console.WriteLine(FullBinaryTree.PrintPath(FullBinaryTree.QuickFindPath(nodeA, nodeB)));
Console.WriteLine();
nodeB = new BinaryTreeNode<int>(301);
Console.WriteLine($"[A({nodeA.Value})]->[B({nodeB.Value})]");
path = FullBinaryTree.FindPath(nodeA, nodeB);
Console.WriteLine(FullBinaryTree.PrintPath(path));
Console.WriteLine(FullBinaryTree.PrintPath(FullBinaryTree.QuickFindPath(nodeA, nodeB)));
Console.WriteLine();
Console.ReadKey();
}
}
public static class FullBinaryTree
{
public static BinaryTreeNode<int> CreateTree(int intial, int depth)
{
BinaryTreeNode<int> header = new BinaryTreeNode<int>(intial);
CreateSub(header, intial, 2, depth);
return header;
}
private static void CreateSub(BinaryTreeNode<int> node, int initial, int level, int depth)
{
if (level > depth) return;
int value = (node.Value << 1) - (initial - 1);
BinaryTreeNode<int> leftChildNode = new BinaryTreeNode<int>(value);
BinaryTreeNode<int> rightChildNode = new BinaryTreeNode<int>(value + 1);
node.LeftChildNode = leftChildNode;
node.RightChildNode = rightChildNode;
leftChildNode.ParentNode = node;
rightChildNode.ParentNode = node;
CreateSub(leftChildNode, initial, level + 1, depth);
CreateSub(rightChildNode, initial, level + 1, depth);
}
public static string PrintTree(BinaryTreeNode<int> header)
{
StringBuilder sb = new StringBuilder($"{header.Value}");
if (header.LeftChildNode != null)
{
sb.Append($"({header.LeftChildNode.Value},{header.RightChildNode.Value})");
PrintTreeSub(header.LeftChildNode, sb);
PrintTreeSub(header.RightChildNode, sb);
}
return sb.ToString();
}
private static void PrintTreeSub(BinaryTreeNode<int> node, StringBuilder sb)
{
sb.Append($" {node.Value}");
if (node.LeftChildNode != null)
{
sb.Append($"({node.LeftChildNode.Value},{node.RightChildNode.Value})");
PrintTreeSub(node.LeftChildNode, sb);
PrintTreeSub(node.RightChildNode, sb);
}
}
public static BinaryTreeNode<int> FindNode(BinaryTreeNode<int> node, int value)
{
if (Equals(node.Value, value)) return node;
if (node.LeftChildNode != null)
{
return FindNode(node.LeftChildNode, value) ?? FindNode(node.RightChildNode, value);
}
return null;
}
public static BinaryTreeNode<int> GetRootNode(BinaryTreeNode<int> node)
{
while (true)
{
if (node.ParentNode == null) break;
if (node.ParentNode.LeftChildNode != node && node.ParentNode.RightChildNode != node) break;
node = node.ParentNode;
}
return node;
}
public static Stack<BinaryTreeNode<int>> FindPath(BinaryTreeNode<int> nodeA, BinaryTreeNode<int> nodeB)
{
BinaryTreeNode<int> rootA = GetRootNode(nodeA);
Stack<BinaryTreeNode<int>> path = new Stack<BinaryTreeNode<int>>();
BinaryTreeNode<int> node = nodeA;
path.Push(node);
bool find = FindPathSub(node, nodeB, path);
if (!find)
{
while (!find)
{
if (node.ParentNode == null) break;
if (node.ParentNode == rootA && (node != rootA.LeftChildNode && node != rootA.RightChildNode)) break;
path.Push(node.ParentNode);
int state = 0;
if (node.ParentNode.LeftChildNode == node)
state = 1;
else if (node.ParentNode.RightChildNode == node)
state = 2;
if (state == 0 || state == 1)
{
find = FindPathSub(node.ParentNode.RightChildNode, nodeB, path);
if (find) break;
}
if (state == 0 || state == 2)
{
find = FindPathSub(node.ParentNode.LeftChildNode, nodeB, path);
if (find) break;
}
node = node.ParentNode;
}
}
return find ? path : null;
}
private static bool FindPathSub(BinaryTreeNode<int> node, BinaryTreeNode<int> search, Stack<BinaryTreeNode<int>> path)
{
path.Push(node);
if (node == search) return true;
if (node.LeftChildNode != null)
{
if (FindPathSub(node.LeftChildNode, search, path)) return true;
if (FindPathSub(node.RightChildNode, search, path)) return true;
}
path.Pop();
return false;
}
public static List<BinaryTreeNode<int>> GetRootNodePath(BinaryTreeNode<int> node)
{
List<BinaryTreeNode<int>> path = new List<BinaryTreeNode<int>>();
path.Add(node);
while (true)
{
if (node.ParentNode == null) break;
if (node.ParentNode.LeftChildNode != node && node.ParentNode.RightChildNode != node) break;
node = node.ParentNode;
path.Add(node);
}
return path;
}
public static List<BinaryTreeNode<int>> QuickFindPath(BinaryTreeNode<int> nodeA, BinaryTreeNode<int> nodeB)
{
List<BinaryTreeNode<int>> pathA = GetRootNodePath(nodeA);
List<BinaryTreeNode<int>> pathB = GetRootNodePath(nodeB);
BinaryTreeNode<int> rootA = pathA[pathA.Count - 1];
BinaryTreeNode<int> rootB = pathB[pathB.Count - 1];
if (rootA == rootB)
{
int i = pathA.Count - 2;
int j = pathB.Count - 2;
for (; i >= 0 && j >= 0; i--, j--)
{
if (pathA[i] != pathB[j]) break;
}
if (pathA.Count - 2 > i) pathA.RemoveRange(i + 2, pathA.Count - i - 2);
pathB.RemoveRange(j + 1, pathB.Count - j - 1);
pathB.Reverse();
pathA.AddRange(pathB);
return pathA;
}
else
{
BinaryTreeNode<int> node = rootA;
while (node.ParentNode != null)
{
node = node.ParentNode;
if (node == rootB)
{
pathB.Reverse();
pathA.AddRange(pathB);
return pathA;
}
else if (node == rootA)
{
break;
}
pathA.Add(node);
}
return null;
}
}
public static string PrintPath(IEnumerable<BinaryTreeNode<int>> path)
{
if (path == null) return "No Path!";
IEnumerable<BinaryTreeNode<int>> p = path;
if (path is Stack<BinaryTreeNode<int>>)
{
p = p.Reverse();
}
StringBuilder sb = new StringBuilder();
foreach (var item in p)
{
sb.Append($"{item.Value}->");
}
sb.Remove(sb.Length - 2, 2);
return sb.ToString();
}
}
public class BinaryTreeNode<T> where T : struct
{
public T Value { get; set; }
public BinaryTreeNode<T> ParentNode { get; set; }
public BinaryTreeNode<T> LeftChildNode { get; set; }
public BinaryTreeNode<T> RightChildNode { get; set; }
public BinaryTreeNode() { Value = default; }
public BinaryTreeNode(T value) { Value = value; }
}
}