【說明】:
本文是左程雲老師所著的《程序員面試代碼指南》第三章中“二叉樹的序列化和反序列化”這一題目的C++復現。
本文只包含問題描述、C++代碼的實現以及簡單的思路,不包含解析說明,具體的問題解析請參考原書。
感謝左程雲老師的支持。
【題目】:
二叉樹被記錄成文件的過程叫作二叉樹的序列化,通過文件內容重建原來二叉樹的過程叫做二叉樹的反序列化。給定一顆二叉樹的頭節點 head,並已知二叉樹節點值的類型為32位整形。請設計一種二叉樹序列化和反序列化的方案,並用代碼實現。
【思路】:
解法為先序遍歷和層遍歷兩種。
【編譯環境】:
CentOS6.7(x86_64)
gcc 4.4.7
【實現及測試】:
聲明代碼:
/* *文件名:bt_serial.h *作者: *摘要:實現二叉樹的序列化和反序列化 */ #include <string> using namespace std; class Node { public: Node(int data) { value = data; left = NULL; right = NULL; } public: int value; Node *left; Node *right; }; string serialByPre(Node *root); //通過先序遍歷序列化為字符串 Node* reconByPreString(string preStr); //將通過先序遍歷序列化得到的的字符串反序列化 string serialByLevel(Node *root); //按層遍歷序列化 Node* reconByLevelString(string levelStr);//根據層遍歷反序列化
實現及測試代碼:
/* *文件名:bt_serial.cpp *作者: *摘要:二叉樹序列化與反序列化的實現 */ #include "bt_serial.h" #include <queue> #include <sstream> #include <iostream> //字符串轉換為整形 int strToint(string &svalue) { stringstream ss; ss << svalue; int ivalue; ss >> ivalue; return ivalue; } //整形轉換為字符串 string intTostr(int &ivalue) { stringstream ss; ss << ivalue; string svalue; ss >> svalue; return svalue; } string serialByPre(Node *root) { if(NULL == root) return "#!"; string svalue = intTostr(root->value); string res = svalue + "!"; res += serialByPre(root->left); res += serialByPre(root->right); return res; } Node* reconPreOrder(queue<string> *q) { string svalue = q->front(); q->pop(); // cout << svalue << endl; if("#" == svalue) return NULL; int ivalue = strToint(svalue); Node *root = new Node(ivalue); root->left=reconPreOrder(q); root->right=reconPreOrder(q); return root; } Node* reconByPreString(string preStr) { size_t firPos = 0; size_t secPos = 0; queue<string>* q = new queue<string>; //注意指針的使用 secPos = preStr.find("!"); while(secPos != string::npos) { q->push(preStr.substr(firPos, secPos - firPos)); firPos = secPos + 1; secPos = preStr.find("!", firPos); } return reconPreOrder(q); } string serialByLevel(Node* root) { if(NULL == root) return "#!"; string svalue = intTostr(root->value); string res = svalue + "!"; queue<Node*> q; q.push(root); while(!q.empty()) { root = q.front(); q.pop(); if(NULL != root->left) { svalue = intTostr(root->left->value); res += svalue + "!"; q.push(root->left); } else { res += "#!"; } if(NULL != root->right) { svalue = intTostr(root->right->value); res += svalue + "!"; q.push(root->right); } else { res += "#!"; } } return res; } Node* generateNodeByString(string val) { if("#" == val) return NULL; return new Node(strToint(val)); } Node* reconByLevelString(string levelStr) { size_t firPos = 0; size_t secPos = levelStr.find("!"); queue<string>* qStr = new queue<string>; //注意指針的使用 while(secPos != string::npos) { qStr->push(levelStr.substr(firPos, secPos - firPos)); // cout << qStr->back() << endl; firPos = secPos + 1; secPos = levelStr.find("!", firPos); } queue<Node*>* qNode = new queue<Node*>; //注意指針的使用 Node *root = generateNodeByString(qStr->front()); qStr->pop(); if (NULL != root) qNode->push(root); Node *node = NULL; while(!qNode->empty()) { node = qNode->front(); qNode->pop(); if (NULL != node) cout << node->value << endl; else cout << "#" << endl; node->left = generateNodeByString(qStr->front()); qStr->pop(); node->right = generateNodeByString(qStr->front()); qStr->pop(); if(NULL != node->left) qNode->push(node->left); if(NULL != node->right) qNode->push(node->right); } return root; } int main() { string str = "12!3!#!#!#!"; Node *root = reconByPreString(str); string str1 = serialByPre(root); cout << str1 << endl; root = reconByLevelString(str); str1 = serialByLevel(root); cout << str1 << endl; return 0; }
說明:
由JAVA代碼轉到C++代碼,像字符串類、隊列類的在使用上的差距比較大。但是整體的思路還是左老師在書中所提出的。
注:
轉載請注明出處;
轉載請注明源思路來自於左程雲老師的《程序員代碼面試指南》。
