C# - pre-order serialize - very compact, no commas, no null, no separators
Here is the idea.  Each node can be serialized with a prefix char and and Abs value.  The prefix char acts as the separator and denotes the sign of the value an
Here is the idea.  Each node can be serialized with a prefix char and and Abs value.  The prefix char acts as the separator and denotes the sign of the value and if the value has a left or right or both or is a leaf.\n\nI use this code but any similar codes could be used\n```\n'x' = leaf\n'l' = left node only\n'r' = right node only\n'f' = full or both left and right\n```\n\nif the value is negative I take the capitalization of the prefix\n```\n'X' = leaf and negative value\n'L' = left node only and negative value\n'R' = right node only and negative value\n'F' = full or both left and right and negative value\n```\n\nFor example:\nA node with value "2" and a left node only\n```\nl2\n```\nA node with a value of "-1234" which is a leaf\n```\nX1234\n```\n\nThese could be strung together to form a root "2" with left node leaf "-1234"\n```\nl2X1234\n```\n\nThis could be further optimized by choosing codes in the upper alphabet and serializing numbers in hex.  And of course you could compact this even further by using a binary system and encoding as integers.  But I thought the main trick here of using the prefix was the piece I wanted to share.\n\n```\n \n    public class Codec\n    {\n        // Encodes a tree to a single string.\n        public string serialize(TreeNode root)\n        {\n            StringBuilder sb = new StringBuilder();\n            BuildSerialize(root, sb);\n            return sb.ToString();\n        }\n\n        // Decodes your encoded data to tree.\n        public TreeNode deserialize(string data)\n        {\n            NodeIter nodeIter = new NodeIter(data);\n            TreeNode root = this.BuildDeserialize(nodeIter);\n            return root;\n        }\n\n        private void BuildSerialize(TreeNode node, StringBuilder sb)\n        {\n            // pre-order\n            if (node == null) return;\n            sb.Append(SerializeNode(node));\n            BuildSerialize(node.left, sb);\n            BuildSerialize(node.right, sb);\n        }\n\n        private string SerializeNode(TreeNode node)\n        {\n            if (node == null) return "";\n\n            char c = '$';\n            if (node.left != null && node.right != null) c = 'f'; // full - both left and right\n            else if (node.left != null) c = 'l'; // left only\n            else if (node.right != null) c = 'r'; // right only\n            else c = 'x'; // leaf\n\n            if (node.val < 0) c = Char.ToUpper(c); // negative value identified by upper case\n\n            return c.ToString() + Math.Abs(node.val).ToString();\n        }\n\n        private TreeNode BuildDeserialize(NodeIter nodeIter)\n        {\n            TreeNode node = nodeIter.Next();\n            if (node == null) return node;\n            if (node.left != null)\n            {\n                node.left = BuildDeserialize(nodeIter);\n            }\n            if (node.right != null)\n            {\n                node.right = BuildDeserialize(nodeIter);\n            }\n            return node;\n        }\n    }\n\n    public class NodeIter\n    {\n        private string str = null;\n        private int pos = 0;\n        public NodeIter(string s)\n        {\n            this.str = s == null ? "" : s;\n        }\n\n        public TreeNode Next()\n        {\n            TreeNode node = null;\n            if (this.pos < this.str.Length)\n            {\n                node = new TreeNode(1);\n                char c = this.str[this.pos];\n                if (Char.IsUpper(c)) node.val = -1;\n                switch (Char.ToLower(c))\n                {\n                    case 'x': break;\n                    case 'l': node.left = new TreeNode(0); break;\n                    case 'r': node.right = new TreeNode(0); break;\n                    case 'f': node.left = new TreeNode(0); node.right = new TreeNode(0); break;\n                    default: break;\n                }\n\n                this.pos++;\n                int val = 0;\n                while (this.pos < this.str.Length && Char.IsDigit(this.str[this.pos]))\n                {\n                    val = val * 10 + this.str[this.pos] - '0';\n                    this.pos++;\n                }\n                node.val *= val;\n            }\n            return node;\n        }\n    }\n```
[]