forked from kodecocodes/swift-algorithm-club
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
adf6065
commit f5c74b9
Showing
1 changed file
with
40 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,49 @@ | ||
# Encode and Decode Binary Tree | ||
|
||
We need to design an algorithm to encode and decode a binary tree. | ||
* **Encode**: Convert a tree into a string that can be stored in the disk. | ||
* **Decode**: Given the encoded string, you need to convert it into a Tree. | ||
> **Note**: The prerequisite for this article is an understanding of how [binary trees](https://github.com/raywenderlich/swift-algorithm-club/tree/master/Binary%20Tree) work. | ||
For example, you may serialize the following tree | ||
Trees are complex structures. Unlike linear collections such as arrays or linked lists, trees are *non-linear* and each element in a tree has positional information such as the *parent-child* relationship between nodes. When you want to send a tree structure to your backend, you need to send the data of each node, and a way to represent the parent-child relationship for each node. | ||
|
||
Your strategy in how you choose to represent this information is called your **encoding** strategy. The opposite of that - changing your encoded data back to its original form - is your **decoding** strategy. | ||
|
||
as "[1,2,3,null,null,4,5]", just the same as how LeetCode OJ serializes a binary tree. You do not necessarily need to follow this format, so please be creative and come up with different approaches yourself. | ||
Note: Do not use class member/global/static variables to store states. Your serialize and deserialize algorithms should be stateless. | ||
There are many ways to encode a tree and decode a tree. The important thing to keep in mind is that encoding and decoding strategies are closely related. The way you choose to encode a tree directly affects how you might decode a tree. | ||
|
||
## Solution | ||
For example, given a tree like this | ||
> a | ||
> / \\ | ||
> | ||
> b c | ||
> | ||
> / \\ | ||
> d e | ||
Encoding and decoding are synonyms to *serializing* and *deserializing* trees. | ||
|
||
We can use inorder traversal to convert the tree into the string like this `a b # # c d # # e # #` | ||
As a reference, the following code represents the typical `Node` type of a binary tree: | ||
|
||
So, the idea is for the empty node, we use `#` to represent. | ||
```swift | ||
class BinaryNode<Element: Comparable> { | ||
var data: Element | ||
var leftChild: BinaryNode? | ||
var rightChild: BinaryNode? | ||
|
||
// ... (rest of the implementation) | ||
} | ||
``` | ||
|
||
## Encoding | ||
|
||
As mentioned before, there are different ways to do encoding. For no particular reason, you'll opt for the following rules: | ||
|
||
1. The result of the encoding will be a `String` object. | ||
2. You'll encode using *pre-order* traversal. | ||
|
||
Here's an example of this operation in code: | ||
|
||
```swift | ||
extension BinaryNode { | ||
var encodedString: String { | ||
var str = "" | ||
preOrderTraversal { str.append($0) } | ||
return str | ||
} | ||
|
||
func preOrderTraversal(visit: (T) -> ()) { | ||
visit(data) | ||
leftChild?.preOrderTraversal(visit: visit) | ||
rightChild?.preOrderTraversal(visit: visit) | ||
} | ||
} | ||
``` | ||
|
||
For the decode process, we can still use inorder to convert the string back to a tree. |