二叉樹序列化


文件的大小盡可能的小。

     想了四種方法:

     第一種方法:把二叉樹按前序和中序遍歷一遍,存兩次二叉樹。

     第二種方法:將二叉樹按左枝為0,右枝為1進行路徑編碼,那么每個節點都可以表示成,節點信息和路徑信息進行永久化。 
     第三種方法:將二叉樹變成滿二叉樹,采用數組存儲滿二叉樹,那么數據index和根據二叉樹的節點信息進行永久化。

0 1 2 3 4 5 6 7 8 9
ROOT L R LL LR RL RR LLL LLR LRL


     第四種方法:采用一個位圖和所有節點信息進行存儲,位圖上的0代表着相應滿二叉樹的節點沒有節點,1代表有節點信息。
     四種方法比較:第一種方法,冗余信息量剛好是原有數據的兩倍。
                                 第二種方法存儲的是節點信息和路徑信息,冗余信息量是(路徑信息*節點數)
                                 第三種方法:冗余信息為,sizeof(unsigned int) * 節點數
                                 第四種方法:冗余信息為樹的層數K,(2^k -1)bit 
      因此第四種方法在二叉樹是滿二叉樹或者二叉樹的層數比較小的情況下,信息量比較小,但是在樹的層比較豐富的情況下,冗余信息非常大。我覺得也不是什么特別好的方法。貌似我還是沒有得到正確答案。

[html] view plaincopyprint?
  1. #include<iostream>  
  2. #include <fstream>  
  3. #include<math.h>  
  4.   
  5. #define  max(a,b) ((a)>(b)?(a):(b))  
  6.   
  7. using namespace std;  
  8. //隨機數大小  
  9. const int NUMBER = 9;  
  10. //修改樹的深度  
  11. const int DEPTH = 6;  
  12.   
  13. //文件流  
  14. ofstream fout3("serialize3.txt");  
  15. ofstream fout4("serialize4.txt");  
  16. ofstream fout("tree.txt");  
  17.   
  18. //樹節點信息  
  19. typedef struct Node  
  20. {  
  21.     int data;  
  22.     Node * left;  
  23.     Node * right;  
  24. } BinaryTree;  
  25.   
  26.   
  27. //隨機生成二叉樹  
  28. void generate(Node ** tree, int d)  
  29. {  
  30.     *tree = (Node *)malloc(sizeof(Node));  
  31.     (*tree)->data = rand()%NUMBER + 1;  
  32.   
  33.     int isleft = rand()%DEPTH;  
  34.     if(d+isleft < DEPTH)  
  35.         generate(&((*tree)->left), d+1);  
  36.     else  
  37.         (*tree)->left = NULL;  
  38.       
  39.     int isright = rand()%DEPTH;  
  40.     if (d+isright < DEPTH)  
  41.     {  
  42.         generate(&((*tree)->right), d+1);  
  43.     }  
  44.     else  
  45.         (*tree)->right = NULL;  
  46. }  
  47.   
  48. //獲取樹的深度  
  49. int getTreeDepth(Node * tree)  
  50. {  
  51.     if (tree == NULL)  
  52.     {  
  53.         return 0;  
  54.     }  
  55.     int left = getTreeDepth(tree->left);  
  56.     int right = getTreeDepth(tree->right);  
  57.       
  58.     return (max( left, right ) + 1);  
  59. }  
  60.   
  61. //打印第i層樹  
  62. void printTreeLevel(Node * tree, int index, int level,int depth)  
  63. {  
  64.     if(tree == NULL)  
  65.     {  
  66.         int length = pow(2.0,(depth-index))-1;  
  67.         for (int i=1; i <= length; i ++)  
  68.         {  
  69.             fout << "  ";  
  70.             cout <<" ";  
  71.         }  
  72.         return;  
  73.     }  
  74.     if(index == level)  
  75.     {  
  76.         //左子樹寬度  
  77.         int length = pow(2.0,(depth-level-1))-1;  
  78.         for (int j=1; j <= length; j ++)  
  79.         {  
  80.             fout <<"  ";  
  81.             cout <<" ";  
  82.         }  
  83.         fout << tree->data;  
  84.         cout << tree->data;  
  85.         //右子樹寬度  
  86.         for (int j=1; j <= length; j ++)  
  87.         {  
  88.             fout <<"  ";  
  89.             cout <<" ";  
  90.         }  
  91.         return;  
  92.     }  
  93.   
  94.     printTreeLevel(tree->left, index +1,level, depth);  
  95.     fout <<"  ";  
  96.     cout <<" ";  
  97.     printTreeLevel(tree->right, index+1, level, depth);  
  98. }  
  99.   
  100. //逐層遍歷二叉樹  
  101. //兩種思路,一種采用廣度遍歷的方法,利用鏈表空間逐層存儲,逐層打印  
  102. //一種使用遞歸的方法逐層打印  
  103. void printTree(Node * tree)  
  104. {  
  105.     int depth = getTreeDepth(tree);  
  106.   
  107.     for (int i=0; i < depth; i ++)  
  108.     {  
  109.         printTreeLevel(tree, 0, i,depth);  
  110.         fout << endl;  
  111.         cout <<endl;  
  112.     }  
  113. }  
  114.   
  115. //序列化,四種方法  
  116. //第一種方法:把二叉樹按前序和中序遍歷一遍,存兩次二叉樹。  
  117. //第二種方法:將二叉樹按左枝為0,右枝為1進行路徑編碼,那么每個節點都可以表示成,節點信息和路徑信息進行永久化。  
  118. //第三種方法:將二叉樹變成滿二叉樹,采用數組存儲滿二叉樹,那么數據index和根據二叉樹的節點信息進行永久化。  
  119. //第四種方法:采用一個位圖和所有節點信息進行存儲,位圖上的0代表着相應滿二叉樹的節點沒有節點,1代表有節點信息。  
  120. //四種方法比較:第一種方法,冗余信息量剛好是原有數據的兩倍。  
  121. //第二種方法存儲的是節點信息和路徑信息,冗余信息量是(路徑信息*節點數)  
  122. //第三種方法:冗余信息為,sizeof(unsigned int) * 節點數  
  123. //第四種方法:冗余信息為樹的層數K,(2^k -1)bit   
  124. //因此第四種方法在二叉樹是滿二叉樹或者二叉樹的層數比較小的情況下,信息量比較小,但是在樹的層比較豐富的情況下,  
  125. //冗余信息非常大。我覺得也不是什么特別好的方法。貌似我還是沒有得到正確答案。  
  126.   
  127. //第三種方法序列化  
  128. void serialize_3(Node *tree, unsigned int index)  
  129. {  
  130.     if (tree == NULL)  
  131.     {  
  132.         return;  
  133.     }  
  134.       
  135.     fout3 << tree->data << " " << index << endl;  
  136.     serialize_3(tree->left, index*2);  
  137.     serialize_3(tree->right, index*2 +1);  
  138. }  
  139.   
  140. //設置bitmap  
  141. void setbitmap(Node * tree, int * map,unsigned int bit, int level)  
  142. {  
  143.     if (tree == NULL)  
  144.     {  
  145.         return;  
  146.     }  
  147.       
  148.     unsigned int index = bit / 32;  
  149.     unsigned int b = bit%32;  
  150.     map[index] = map[index] | (1<<b);  
  151.     fout4 << tree->data << " ";  
  152.     setbitmap(tree->left, map,  bit * 2+1, level+1);  
  153.     setbitmap(tree->right, map, bit * 2 +2 , level+1);  
  154. }  
  155.   
  156. //第四種方法永久化  
  157. void seralize_4(Node* tree)  
  158. {  
  159.     int depth = getTreeDepth(tree);  
  160.       
  161.     int len = (depth-5)>0? (depth-5) : 0;  
  162.     len = (1<<len);  
  163.     int* map = new int[len];  
  164.     memset(map, 0, sizeof(int) * len);  
  165.     setbitmap(tree, map, 0, 1);  
  166.   
  167.     fout4<<endl;  
  168.   
  169.     for (int i=0; i <len; i ++)  
  170.     {  
  171.         fout4 <<hex << map[i];  
  172.     }  
  173.     fout4 <<endl;  
  174.     delete [] map;  
  175. }  
  176.   
  177. //釋放內存  
  178. void deleteTree(Node * tree)  
  179. {  
  180.     if (tree == NULL)  
  181.     {  
  182.         return;  
  183.     }  
  184.     deleteTree(tree->left);  
  185.     deleteTree(tree->right);  
  186.     free(tree);  
  187. }  
  188.   
  189. int main()  
  190. {  
  191.     BinaryTree * tree=NULL;  
  192.   
  193.     //隨機生成二叉樹  
  194.     cout << "隨機生成二叉樹,並保存到tree.txt"<<endl;  
  195.     generate(&tree, 0);  
  196.   
  197.     //樹層比較低的,打印出二叉樹  
  198.     if (DEPTH <= 15)  
  199.     {  
  200.         printTree(tree);  
  201.     }  
  202.   
  203.     //第三種序列化方法  
  204.     cout << "用第三種方法持久化到serialize3.txt" <<endl;  
  205.     serialize_3(tree, 1);  
  206.   
  207.     //第四種序列化方法  
  208.     cout <<"用第四種方法持久化到serialize4.txt" <<endl;  
  209.     seralize_4(tree);  
  210.   
  211.     //回收空間  
  212.     deleteTree(tree);  
  213.     system("pause");  
  214.     return 0;  
  215. }  


    運行效果:

    第一步,隨機生成一個二叉樹,並逐層打印,然后采用兩種序列化方法進行序列化。


     第三種序列化文件為:

[html] view plaincopyprint?
  1. 6 1  
  2. 8 2  
  3. 9 4  
  4. 8 5  
  5. 3 11  
  6. 7 22  
  7. 9 23  
  8. 7 3  
  9. 1 6  
  10. 8 12  
  11. 6 24  
  12. 3 49  
  13. 9 7  
  14. 4 15  
  15. 3 31  
    第四種序列化方法為:

[html] view plaincopyprint?
  1. 6 8 9 8 3 7 9 7 1 8 6 3 9 4 3       --數據  
  2. 40e04c7f10000                       --位圖,用16進制表示  
   如上面分析的一樣,第四種方法在二叉樹是滿二叉樹或者二叉樹的層數比較小的情況下,信息量比較小,但是在樹的層比較豐富的情況下,冗余信息非常大。如在15層的二叉樹中:
[html] view plaincopyprint?
  1. 6 8 9 4 8 3 7 6 4 1 1 6 3 7 9 8 3 7 3 6 3 8 3 7 2 5 6 4 3 1 8 4 2 2 4 3 4 1 9 6 7 4 7 9 5 8 8 7 3 7 9 3 6 3 9 3 3 2 3 5 1 7 5 1 3 9 2 1 3 1 3 3 6 6 2 7 9 4 6 2 7 9 3 2 1 7 4 3 3 1 9 3 1 9 7 6 1 8 8 7 3 2 6 6 8 5 2 3 8 2 5 5 9 4 6 9 2 3 1 2 2 5 2 1 9 9 4 7 6 4 8 5 9 4 8 9 9 9 6 9 5 8 3 9 9 8 3 9 3 5 6 9 6 2 2 6 2 2 5 1 2 1 1 5 6 9 9 5 8 9 5 4 3 8 6 2 3 4 9 9 2 7 7 8 7 6 7 2 2 9 8 1 3 1 3 3 4 3 3 7 3 5 7 9 7 2 4 3 5 2 1 5 3 9 2 8 3 6 3 2 2 1 2 9 3 1 5 5 8 2 4 6 3 4 2 5 5 5 7 6 4 6 5 8 6 2 5 9 6 3 6 3 1 8 1 9 4 6 9 2 4 1 1 5 3 7 2 2 7 1 8 3 4 9 2 6 9 3 8   
  2. 3e8ffbff1f7901eb3d9867fe6004a7860038b380000606daf48130098068070189048001e8000009022418079e361e000007000838000794808400040800000001f1800018000820008006605401300580650004600000002e82801d8000802120000000018000000002c000118000008000000060000404105800000000400000100000000001928001000800001a21100000000000000008000000020000000000860000000020030000004000000020042000000000000000000000000000000200400098000005000000020000000000000000000000000000000000080000000000000000000000400000000000000000000002000000020180000100000000000000000000000000000000000000000000000000000000000000020000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000002000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000  

    信息量隨着層數的增加,信息量成幾何級擴大。但是,研究16進制字符串位圖數據可以發現里面的數據0出現的特別多,因此下一步可以采用huffman編碼等壓縮編碼方式對字符串數據進行數據壓縮。

    下一步:采用二進制編碼對位圖數據進行數據壓縮。






注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



二叉樹的序列化 序列化二叉樹 序列化二叉樹 序列化二叉樹 62:序列化二叉樹 序列化二叉樹 序列化二叉樹 序列化二叉樹 【二叉樹】二叉樹序列化和反序列化 二叉樹基礎之序列化和反序列化二叉樹
 
粤ICP备14056181号  © 2014-2021 ITdaan.com