数的节点代表集合,根代表关系
树-广度优先遍历(层序遍历)
树-深度优先遍历(深度遍历)
用于判断父子节点关系
二叉树
1、每个节点度最多为2
2、度为0的节点比度为2的节点多1个:
完全二叉树,满二叉树,完美二叉树
完全二叉树 (complete binary tree)
1、编号为 i 的子节点:
- 左孩子编号:2i
- 右孩子编号:2i+1
2、可以用连续空间存储(数组) 通过计算而非记录得到子节点地址,节省空间 左孩子右兄弟表示法节省空间
二叉树代码演示
struct Node {
int key;
Node *lchild, *rchild;
Node(int key) : key(key), lchild(NULL), rchild(NULL) {}
};
Node* getNewNode(int key) {
return new Node(key);
}
Node* insert(Node* root, int key) {
if (root == NULL) return getNewNode(key);
if (rand() % 2) root->lchild = insert(root->lchild, key);
else root->rchild = insert(root->rchild, key);
return root;
}
void clear(Node* root) {
if (root == NULL) return;
clear(root->lchild);
clear(root->rchild);
delete root;
}
void bfs(Node* root) {//广度优先遍历
if (root == NULL) return;
queue<Node*> q;
q.push(root);
while (!q.empty()) {
Node* node = q.front();
q.pop();
cout << "\nnode : " << node->key << "\n";
if (node->lchild) {
q.push(node->lchild);
cout <<"\t"<< node->key <<"->"<< node->lchild->key <<"(left)\n";
}
if (node->rchild) {
q.push(node->rchild);
cout <<"\t"<< node->key <<"->"<< node->rchild->key <<"(right)\n";
}
}
}
int tot = 0;
void dfs(Node* root) {//深度优先遍历
if (root == NULL) return;
int start, end;
tot += 1;
start = tot;
if (root->lchild) dfs(root->lchild);
if (root->rchild) dfs(root->rchild);
tot += 1;
end = tot;
cout << root->key << " : [" << start << ", " << end << "]\n";
}
用其中两种遍历(必须含中序遍历)就可以恢复二叉树
class Node {
public:
int key;
int ltag, rtag; // 1 : thread, 0 : edge
Node *lchild, *rchild;
Node(int key) : key(key), ltag(0), rtag(0), lchild(nullptr), rchild(nullptr) {}
};
class ThreadedBinaryTree {
public:
Node *root;
Node *pre_node;
Node *inorder_root;
ThreadedBinaryTree():root(nullptr),pre_node(nullptr),inorder_root(nullptr) {}
Node* insert(Node *root, int key) {
if (root == nullptr) return new Node(key);
if (rand() % 2) root->lchild = insert(root->lchild, key);
else root->rchild = insert(root->rchild, key);
return root;
}
void clear(Node *root) {
if (root == nullptr) return;
if (root->ltag == 0) clear(root->lchild);
if (root->rtag == 0) clear(root->rchild);
delete root;
}
void pre_order(Node *root) const {
if (root == nullptr) return;
cout << root->key << " ";
if (root->ltag == 0) pre_order(root->lchild);
if (root->rtag == 0) pre_order(root->rchild);
}
void in_order(Node *root) const {
if (root == nullptr) return;
if (root->ltag == 0) in_order(root->lchild);
cout << root->key << " ";
if (root->rtag == 0) in_order(root->rchild);
}
void post_order(Node *root) const {
if (root == nullptr) return;
if (root->ltag == 0) post_order(root->lchild);
if (root->rtag == 0) post_order(root->rchild);
cout << root->key << " ";
}
void __build_inorder_thread(Node *root) {
if (root == nullptr) return;
if (root->ltag == 0) __build_inorder_thread(root->lchild);
if (inorder_root == nullptr) inorder_root = root;
if (root->lchild == nullptr) {
root->lchild = pre_node;
root->ltag = 1;
}
if (pre_node && pre_node->rchild == nullptr) {
pre_node->rchild = root;
pre_node->rtag = 1;
}
pre_node = root;
if (root->rtag == 0) __build_inorder_thread(root->rchild);
}
void build_inorder_thread(Node *root) {
__build_inorder_thread(root);
if (pre_node) {
pre_node->rchild = nullptr;
pre_node->rtag = 1;
}
}
Node* getNext(Node *root) {
if (root->rtag == 1) return root->rchild;
root = root->rchild;
while (root->ltag == 0 && root->lchild) root = root->lchild;
return root;
}
};
二叉树的广义表表示法
class Node {
public:
int key;
Node *lchild, *rchild;
Node(int key) : key(key), lchild(nullptr), rchild(nullptr) {}
};
Node* insert(Node* root, int key) {
if (root == nullptr) return new Node(key);
if (rand() % 2) root->lchild = insert(root->lchild, key);
else root->rchild = insert(root->rchild, key);
return root;
}
Node* getRandomBinaryTree(int n) {
Node* root = nullptr;
for (int i = 0; i < n; i++) {
root = insert(root, rand() % 100);
}
return root;
}
void clear(Node* root) {
if (root == nullptr) return;
clear(root->lchild);
clear(root->rchild);
delete root;
}
string buff;
int len = 0;
void __serialize(Node* root) {//二叉树转广义表
if (root == nullptr) return;
buff += to_string(root->key);
if (root->lchild == nullptr && root->rchild == nullptr) return;
buff += "(";
__serialize(root->lchild);
if (root->rchild) {
buff += ",";
__serialize(root->rchild);
}
buff += ")";
}
string serialize(Node* root) {
buff.clear();
len = 0;
__serialize(root);
return buff;
}
void print(Node* node) {
if (node == nullptr) return;
cout << node->key << "("
<< (node->lchild ? node->lchild->key : -1) << ", "
<< (node->rchild ? node->rchild->key : -1) << ")\n";
}
void output(Node* root) {
if (root == nullptr) return;
print(root);
output(root->lchild);
output(root->rchild);
}
Node* deserialize(const string& buff) {//广义表转二叉树
stack<Node*> s;
int flag = 0, scode = 0;
Node* p = nullptr, * root = nullptr;
for (size_t i = 0; i < buff.size(); i++) {
switch (scode) {
case 0: {
if (buff[i] >= '0' && buff[i] <= '9') scode = 1;
else if (buff[i] == '(') scode = 2;
else if (buff[i] == ',') scode = 3;
else scode = 4;
i -= 1;
} break;
case 1: {
int key = 0;
while (i < buff.size() && buff[i] >= '0' && buff[i] <= '9') {
key = key * 10 + (buff[i] - '0');
i += 1;
}
p = new Node(key);
if (!s.empty() && flag == 0) s.top()->lchild = p;
if (!s.empty() && flag == 1) s.top()->rchild = p;
i -= 1;
scode = 0;
} break;
case 2: {
s.push(p);
flag = 0;
scode = 0;
} break;
case 3: {
flag = 1;
scode = 0;
} break;
case 4: {
root = s.top();
s.pop();
scode = 0;
} break;
}
}
return root;
}
int main() {
Node* root = getRandomBinaryTree(10);
string serialized = serialize(root);
cout << "Serialized: " << serialized << endl;
Node* deserializedRoot = deserialize(serialized);
output(deserializedRoot);
clear(root);
clear(deserializedRoot);
return 0;
}
最优变长编码:哈夫曼编码
定长编码vs变长编码
哈夫曼编码生成过程: 1.首先,统计得到每一种字符的概率 2.每次将最低频率的两个节点合并成一棵子树 3.经过了 n-1 轮合并,就得到了一棵哈夫曼树 4.按照左0,右1的形式,将编码读取出来
结论:哈弗曼编码,是最优的变长编码
证明
代码
class Node {
public:
char ch;
int freq;
Node *lchild, *rchild;
Node(int freq, char ch) : ch(ch), freq(freq), lchild(nullptr), rchild(nullptr) {}
};
Node* getNewNode(int freq, char ch) {
return new Node(freq, ch);
}
void swap_node(vector<Node*>& node_arr, int i, int j) {
Node* temp = node_arr[i];
node_arr[i] = node_arr[j];
node_arr[j] = temp;
}
int find_min_node(const vector<Node*>& node_arr, int n) {
int ind = 0;
for (int j = 1; j <= n; j++) {
if (node_arr[ind]->freq > node_arr[j]->freq) ind = j;
}
return ind;
}
Node* buildHaffmanTree(vector<Node*>& node_arr) {
int n = node_arr.size();
for (int i = 1; i < n; i++) {
// Find two nodes with the smallest frequency
int ind1 = find_min_node(node_arr, n - i);
swap_node(node_arr, ind1, n - i);
int ind2 = find_min_node(node_arr, n - i - 1);
swap_node(node_arr, ind2, n - i - 1);
// Merge two nodes
int freq = node_arr[n - i]->freq + node_arr[n - i - 1]->freq;
Node* node = getNewNode(freq, 0);
node->lchild = node_arr[n - i - 1];
node->rchild = node_arr[n - i];
node_arr[n - i - 1] = node;
}
return node_arr[0];
}
void clear(Node* root) {
if (root == nullptr) return;
clear(root->lchild);
clear(root->rchild);
delete root;
}
unordered_map<char, string> char_code;
void extractHaffmanCode(Node* root, string& buff, int k) {
if (root->lchild == nullptr && root->rchild == nullptr) {
char_code[root->ch] = buff;
return;
}
buff.push_back('0');
extractHaffmanCode(root->lchild, buff, k + 1);
buff.pop_back();
buff.push_back('1');
extractHaffmanCode(root->rchild, buff, k + 1);
buff.pop_back();
}
Leetcode-589 N叉树的前序遍历
class Solution {
public:
void __preorder(Node* root, vector<int>& ans) {
if (root == NULL)
return;
ans.push_back(root->val);
for (auto x : root->children) {
__preorder(x, ans);
}
return;
}
vector<int> preorder(Node* root) {
vector<int> res;
__preorder(root,res);
return res;
}
};
Leetcode-105 从前序与中序遍历序列构造二叉树
class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
if (preorder.size() == 0) return NULL;
int pos = 0, n = preorder.size();
while (inorder[pos] != preorder[0]) pos += 1;
TreeNode *root = new TreeNode(preorder[0]);
vector<int> preArr, inArr;
for (int i = 1; i <= pos; i++) preArr.push_back(preorder[i]);
for (int i = 0; i < pos; i++) inArr.push_back(inorder[i]);
root->left = buildTree(preArr, inArr);
preArr.clear();
inArr.clear();
for (int i = pos + 1; i < n; i++) preArr.push_back(preorder[i]);
for (int i = pos + 1; i < n; i++) inArr.push_back(inorder[i]);
root->right = buildTree(preArr, inArr);
return root;
}
};
Leetcode-102 二叉树的层序遍历
法一:队列
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
if (root == NULL) return vector<vector<int>>();
TreeNode *node;
queue<TreeNode *> q;
q.push(root);
vector<vector<int>> ans;
while (!q.empty()) {
int cnt = q.size();
vector<int> temp;
for (int i = 0; i < cnt; i++) {
node = q.front();
temp.push_back(node->val);
if (node->left) q.push(node->left);
if (node->right) q.push(node->right);
q.pop();
}
ans.push_back(temp);
}
return ans;
}
};
法二:DFS
class Solution {
public:
void dfs(TreeNode *root, int k, vector<vector<int>> &ans) {
if (root == NULL) return ;
if (k == ans.size()) ans.push_back(vector<int>());
ans[k].push_back(root->val);
dfs(root->left, k + 1, ans);
dfs(root->right, k + 1, ans);
return ;
}
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> ans;
dfs(root, 0, ans);//ans是传出参数
return ans;
}
};
Leetcode-226 翻转二叉树
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
if (root == NULL) return NULL;
swap(root->left, root->right);
invertTree(root->left);
invertTree(root->right);
return root;
}
};
Leetcode-107 二叉树的层序遍历Ⅱ
class Solution {
public:
void dfs(TreeNode *root, int k, vector<vector<int>> &ans) {
if (root == NULL) return ;
if (k == ans.size()) ans.push_back(vector<int>());
ans[k].push_back(root->val);
dfs(root->left, k + 1, ans);
dfs(root->right, k + 1, ans);
return ;
}
vector<vector<int>> levelOrderBottom(TreeNode* root) {
vector<vector<int>> ans;
dfs(root, 0, ans);
for (int i = 0, j = ans.size() - 1; i < j; i++, j--) {
swap(ans[i], ans[j]);
}
return ans;
}
};
Leetcode–103 二叉树的锯齿形层序遍历
class Solution {
public:
void dfs(TreeNode *root, int k, vector<vector<int>> &ans) {
if (root == NULL) return ;
if (k == ans.size()) ans.push_back(vector<int>());
ans[k].push_back(root->val);
dfs(root->left, k + 1, ans);
dfs(root->right, k + 1, ans);
return ;
}
vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
vector<vector<int>> ans;
dfs(root, 0, ans); // step1
// step2
for (int k = 1; k < ans.size(); k += 2) {
for (int i = 0, j = ans[k].size() - 1; i < j; i++, j--) {
swap(ans[k][i], ans[k][j]);
}
}
return ans;
}
};
Leetcode-LCR143 子结构判断
class Solution {
public:
bool match_one(TreeNode *A, TreeNode *B) {
if (A == NULL) return B == NULL;
if (B == NULL) return true;
if (A->val != B->val) return false;
return match_one(A->left, B->left) && match_one(A->right, B->right);
}
bool isSubStructure(TreeNode* A, TreeNode* B) {
if (A == NULL) return B == NULL;
if (B == NULL) return false;
if (A->val == B->val && match_one(A, B)) return true;
if (isSubStructure(A->left, B)) return true;
if (isSubStructure(A->right, B)) return true;
return false;
}
};


Comments
Post a Comment