Chinaunix首页 | 论坛 | 博客
  • 博客访问: 161144
  • 博文数量: 34
  • 博客积分: 2070
  • 博客等级: 大尉
  • 技术积分: 277
  • 用 户 组: 普通用户
  • 注册时间: 2010-02-26 19:29
文章分类
文章存档

2015年(2)

2014年(4)

2013年(1)

2012年(1)

2011年(5)

2010年(21)

我的朋友

分类: C/C++

2012-11-28 14:30:52

理论参考: 
维基百科中的红黑树算法介绍的很详细,下面是C++代码实现

  1. #ifndef _FRAME_RBTREE_H_
  2. #define _FRAME_RBTREE_H_

  3. #include <stdint.h>
  4. #include <new>

  5. #define S_OK                            0    

  6. #define E_CONTAIN_FULL                    0x80000001
  7. #define E_NOT_FOUND                        0x80000002

  8. template <typename Key, typename Value, uint32_t DEFAULT_ADD = 1024>
  9. class CRBTree
  10. {
  11. protected:
  12.     enum Color
  13.     {
  14.         enmColor_Red,
  15.         enmColor_Black,
  16.     };

  17. public:
  18.     class Node
  19.     {
  20.     public:
  21.         Key            nKey;
  22.         Value        value;

  23.     private:
  24.         Node        *pParent;
  25.         Node        *pLeft;
  26.         Node        *pRight;
  27.         Color        nColor;

  28.         friend    class CRBTree;

  29.         Node()
  30.         {
  31.             pParent = NULL;
  32.             pLeft    = NULL;
  33.             pRight    = NULL;
  34.             nColor    = enmColor_Red;
  35.         }
  36.     };

  37. public:
  38.     CRBTree()
  39.     {
  40.         m_pRoot = NULL;
  41.         m_pHead = NULL;
  42.         m_pMin = NULL;
  43.         m_nSize = 0;
  44.         m_pBuffer = NULL;
  45.     }

  46.     virtual ~CRBTree()
  47.     {
  48.         Clear();

  49.         while(NULL != m_pBuffer)
  50.         {
  51.             uint8_t *pBuffer = m_pBuffer;
  52.             m_pBuffer = *(uint8_t**)m_pBuffer;
  53.             delete pBuffer;
  54.         }
  55.     }

  56. protected:
  57.     Node* Pop()
  58.     {
  59.         if (NULL == m_pHead)
  60.         {
  61.             Reserve(GetCapacity() + DEFAULT_ADD);
  62.         }

  63.         ++m_nSize;
  64.         Node *pNode = m_pHead;
  65.         m_pHead = pNode->pParent;
  66.         return new(pNode)Node();
  67.     }

  68.     void Push(Node *pNode)
  69.     {
  70.         --m_nSize;
  71.         pNode->~Node();
  72.         pNode->pParent = m_pHead;
  73.         m_pHead = pNode;
  74.     }


  75. public:
  76.     int32_t Insert(const Key nKey, const Value &value)
  77.     {
  78.         Node *pNode = Pop();
  79.         if (NULL == pNode)
  80.         {
  81.             return E_CONTAIN_FULL;
  82.         }
  83.         pNode->nKey = nKey;
  84.         pNode->value = value;

  85.         if ((NULL == m_pMin) || (m_pMin->nKey >= pNode->nKey))
  86.         {
  87.             m_pMin = pNode;
  88.         }

  89.         Node *pParent = FindSite(m_pRoot, nKey);
  90.         if (NULL == pParent)
  91.         {
  92.             m_pRoot = pNode;
  93.             pNode->nColor = enmColor_Black;
  94.             return S_OK;
  95.         }

  96.         pNode->pParent = pParent;
  97.         if (pParent->nKey >= nKey)
  98.         {
  99.             pParent->pLeft = pNode;
  100.         }
  101.         else
  102.         {
  103.             pParent->pRight = pNode;
  104.         }

  105.         InsertRebalance(pNode);
  106.         return S_OK;
  107.     }

  108.     int32_t Delete(const Key nKey)
  109.     {
  110.         Node *pNode = FindNode(nKey);
  111.         if (NULL == pNode)
  112.         {
  113.             return S_OK;
  114.         }

  115.         if (m_pMin == pNode)
  116.         {
  117.             m_pMin = (NULL == pNode->pRight) ? pNode->pParent : FindSite(pNode->pRight, pNode->nKey);
  118.         }

  119.         if ((NULL != pNode->pLeft)
  120.                 && (NULL != pNode->pRight))
  121.         {
  122.             //替换
  123.             Node *pRMinNode = FindSite(pNode->pRight, nKey);    
  124.             Key nKey = pNode->nKey;
  125.             Value value = pNode->value;
  126.             pNode->nKey = pRMinNode->nKey;
  127.             pNode->value = pRMinNode->value;
  128.             pRMinNode->nKey = nKey;
  129.             pRMinNode->value = value;

  130.             pNode = pRMinNode;
  131.         }

  132.         if (pNode == m_pRoot)
  133.         {
  134.             if (NULL != pNode->pLeft)
  135.             {
  136.                 m_pRoot = pNode->pLeft;
  137.                 m_pRoot->pParent = NULL;
  138.             }
  139.             else if (NULL != pNode->pRight)
  140.             {
  141.                 m_pRoot = pNode->pRight;
  142.                 m_pRoot->pParent = NULL;
  143.             }
  144.             else
  145.             {
  146.                 m_pRoot = NULL;
  147.             }
  148.             Push(pNode);
  149.             return S_OK;
  150.         }

  151.         if (enmColor_Black == pNode->nColor)
  152.         {
  153.             Node *pChild = NULL;
  154.             if (NULL != pNode->pLeft)
  155.             {
  156.                 pChild = pNode->pLeft;
  157.             }
  158.             else if (NULL != pNode->pRight)
  159.             {
  160.                 pChild = pNode->pRight;
  161.             }
  162.             if (NULL != pChild)
  163.             {
  164.                 pNode->nColor = pChild->nColor;
  165.             }

  166.             DeleteRebalance(pNode);

  167.             if (NULL != pChild)
  168.             {
  169.                 pChild->nColor = pNode->nColor;
  170.             }
  171.         }

  172.         //删除节点
  173.         Node *pParent = pNode->pParent;
  174.         if (NULL != pNode->pLeft)
  175.         {
  176.             pNode->pLeft->pParent = pParent;
  177.             if (pNode == pParent->pLeft)
  178.             {
  179.                 pParent->pLeft = pNode->pLeft;
  180.             }
  181.             else
  182.             {
  183.                 pParent->pRight = pNode->pLeft;
  184.             }
  185.         }
  186.         else if (NULL != pNode->pRight)
  187.         {
  188.             pNode->pRight->pParent = pParent;
  189.             if (pNode == pParent->pLeft)
  190.             {
  191.                 pParent->pLeft = pNode->pRight;
  192.             }
  193.             else
  194.             {
  195.                 pParent->pRight = pNode->pRight;
  196.             }
  197.         }
  198.         else
  199.         {
  200.             if (pNode == pParent->pLeft)
  201.             {
  202.                 pParent->pLeft = NULL;
  203.             }
  204.             else
  205.             {
  206.                 pParent->pRight = NULL;
  207.             }
  208.         }
  209.         Push(pNode);
  210.         return S_OK;
  211.     }

  212.     int32_t Find(const Key nKey, Value &value)
  213.     {
  214.         Node *pNode = FindNode(nKey);
  215.         if (NULL == pNode)
  216.         {
  217.             return E_NOT_FOUND;
  218.         }
  219.         value = pNode->value;
  220.         return S_OK;
  221.     }

  222.     void Clear()
  223.     {
  224.         while(NULL != Begin())
  225.         {
  226.             Delete(Begin()->nKey);
  227.         }
  228.     }

  229.     void Reserve(const uint32_t nReserveSize)
  230.     {
  231.         const uint32_t nCapacity = GetCapacity();
  232.         if (nReserveSize <= nCapacity)
  233.         {
  234.             return;
  235.         }

  236.         Node arrNode[2];
  237.         const uint64_t nSize = (uint64_t)&arrNode[1] - (uint64_t)&arrNode[0];
  238.         const uint32_t nBlock = (nReserveSize - nCapacity + DEFAULT_ADD - 1) / DEFAULT_ADD;
  239.         for (uint32_t i = 0; i < nBlock; ++i)
  240.         {
  241.             uint8_t *pBuffer = new uint8_t[DEFAULT_ADD * nSize + sizeof(uint8_t*)];

  242.             *(uint8_t**)pBuffer = m_pBuffer;
  243.             m_pBuffer = pBuffer;

  244.             for (uint32_t j = 0; j < DEFAULT_ADD; ++j)
  245.             {
  246.                 Node *pNode = (Node*)(pBuffer + sizeof(uint8_t*) + j * nSize);
  247.                 pNode->pParent = m_pHead;
  248.                 m_pHead = pNode;
  249.             }
  250.         }
  251.     }

  252.     const Node* Begin()
  253.     {
  254.         return m_pMin;
  255.     }

  256.     const Node* Next(const Node *pNode)
  257.     {
  258.         if (NULL == pNode)
  259.         {
  260.             return NULL;
  261.         }
  262.         else if (NULL != pNode->pRight)
  263.         {
  264.             return FindSite(pNode->pRight, pNode->nKey);
  265.         }
  266.         else if (NULL != pNode->pParent)
  267.         {
  268.             while ((NULL != pNode->pParent) && (pNode == pNode->pParent->pRight))
  269.             {
  270.                 pNode = pNode->pParent;
  271.             }
  272.             return pNode->pParent;
  273.         }

  274.         return NULL;
  275.     }

  276.     uint32_t GetSize()
  277.     {
  278.         return m_nSize;
  279.     }

  280.     uint32_t GetCapacity()
  281.     {
  282.         uint32_t nCapacity = 0;
  283.         uint8_t *pBuffer = m_pBuffer;
  284.         while(NULL != pBuffer)
  285.         {
  286.             pBuffer = *(uint8_t**)pBuffer;
  287.             nCapacity += DEFAULT_ADD;
  288.         }

  289.         return nCapacity;
  290.     }

  291. protected:
  292.     Node* FindSite(Node *pNode, const Key nKey)
  293.     {
  294.         if (NULL == pNode)
  295.         {
  296.             return NULL;
  297.         }

  298.         while(true)
  299.         {
  300.             if (pNode->nKey >= nKey)
  301.             {
  302.                 if (NULL == pNode->pLeft)
  303.                 {
  304.                     return pNode;
  305.                 }

  306.                 pNode = pNode->pLeft;
  307.                 continue;
  308.             }
  309.             else
  310.             {
  311.                 if (NULL == pNode->pRight)
  312.                 {
  313.                     return pNode;
  314.                 }
  315.                 pNode = pNode->pRight;
  316.                 continue;
  317.             }
  318.         }
  319.         return NULL;
  320.     }

  321.     Node* FindNode(const Key nKey)
  322.     {
  323.         Node *pNode = m_pRoot;
  324.         if (NULL == pNode)
  325.         {
  326.             return NULL;
  327.         }

  328.         while (true)
  329.         {
  330.             if (pNode->nKey == nKey)
  331.             {
  332.                 return pNode;
  333.             }
  334.             else if (pNode->nKey > nKey)
  335.             {
  336.                 if (NULL == pNode->pLeft)
  337.                 {
  338.                     return NULL;
  339.                 }
  340.                 else
  341.                 {
  342.                     pNode = pNode->pLeft;
  343.                     continue;
  344.                 }
  345.             }
  346.             else
  347.             {
  348.                 if (NULL == pNode->pRight)
  349.                 {
  350.                     return NULL;
  351.                 }
  352.                 else
  353.                 {
  354.                     pNode = pNode->pRight;
  355.                     continue;
  356.                 }
  357.             }
  358.         }
  359.         return NULL;
  360.     }

  361.     void InsertRebalance(Node *pNode)
  362.     {
  363.         while(true)
  364.         {
  365.             //case 1
  366.             if (NULL == pNode->pParent)
  367.             {
  368.                 m_pRoot = pNode;
  369.                 pNode->nColor = enmColor_Black;
  370.                 return;
  371.             }

  372.             //case 2
  373.             Node *pParent = pNode->pParent;
  374.             if (enmColor_Black == pParent->nColor)
  375.             {
  376.                 return;
  377.             }

  378.             //case 3
  379.             Node *pGrandParent = pParent->pParent;
  380.             Node *pUncle = Uncle(pNode);
  381.             if ((NULL != pUncle) && (enmColor_Red == pUncle->nColor))
  382.             {
  383.                 pParent->nColor = enmColor_Black;
  384.                 pUncle->nColor = enmColor_Black;
  385.                 pGrandParent->nColor = enmColor_Red;

  386.                 pNode = pGrandParent;
  387.                 continue;
  388.             }

  389.             //case 4
  390.             if ((pNode == pParent->pRight) && (pParent == pGrandParent->pLeft))
  391.             {
  392.                 RotateLeft(pParent);
  393.                 pNode = pNode->pLeft;
  394.             }
  395.             else if ((pNode == pParent->pLeft) && (pParent == pGrandParent->pRight))
  396.             {
  397.                 RotateRight(pParent);
  398.                 pNode = pNode->pRight;
  399.             }

  400.             //case 5
  401.             pParent = pNode->pParent;
  402.             pGrandParent = pParent->pParent;

  403.             pParent->nColor = enmColor_Black;
  404.             pGrandParent->nColor = enmColor_Red;
  405.             if ((pNode == pParent->pLeft) && (pParent == pGrandParent->pLeft))
  406.             {
  407.                 RotateRight(pGrandParent);
  408.             }
  409.             else
  410.             {
  411.                 RotateLeft(pGrandParent);
  412.             }

  413.             break;
  414.         }

  415.         while((NULL != m_pRoot) && (NULL != m_pRoot->pParent))
  416.         {
  417.             m_pRoot = m_pRoot->pParent;
  418.         }
  419.     }

  420.     void DeleteRebalance(Node* pNode)
  421.     {
  422.         if (enmColor_Red == pNode->nColor)
  423.         {
  424.             pNode->nColor = enmColor_Black;
  425.             return;
  426.         }

  427.         while(true)
  428.         {
  429.             //case 1
  430.             if (NULL == pNode->pParent)
  431.             {
  432.                 break;
  433.             }

  434.             //case 2
  435.             Node *pParent = pNode->pParent;
  436.             //兄弟节点不可能是空节点
  437.             Node *pBrother = Brother(pNode);
  438.             if (enmColor_Red == pBrother->nColor)
  439.             {
  440.                 pParent->nColor = enmColor_Red;
  441.                 pBrother->nColor = enmColor_Black;
  442.                 if (pNode == pParent->pLeft)
  443.                 {
  444.                     RotateLeft(pParent);
  445.                 }
  446.                 else
  447.                 {
  448.                     RotateRight(pParent);
  449.                 }

  450.                 //旋转后兄弟节点位置发生变化
  451.                 pBrother = Brother(pNode);
  452.                 if (NULL == pBrother)
  453.                 {
  454.                     pParent->nColor = enmColor_Black;
  455.                     break;
  456.                 }
  457.             }

  458.             //case 3
  459.             if ((enmColor_Black == pParent->nColor)
  460.                     && SelfAndSonAllBlack(pBrother))
  461.             {
  462.                     pBrother->nColor = enmColor_Red;
  463.                     pNode = pParent;
  464.                     continue;
  465.             }

  466.             //case 4
  467.             if ((enmColor_Red == pParent->nColor)
  468.                     && SelfAndSonAllBlack(pBrother))
  469.             {
  470.                 pBrother->nColor = enmColor_Red;
  471.                 pParent->nColor = enmColor_Black;
  472.                 break;
  473.             }

  474.             //case 5
  475.             if (enmColor_Black == pBrother->nColor)
  476.             {
  477.                 if ((pNode == pParent->pLeft)
  478.                  && (NULL != pBrother->pLeft)
  479.                  && (enmColor_Red == pBrother->pLeft->nColor))
  480.                 {
  481.                     if ((NULL == pBrother->pRight)
  482.                             || (enmColor_Black == pBrother->pRight->nColor))
  483.                     {
  484.                         pBrother->nColor = enmColor_Red;
  485.                         pBrother->pLeft->nColor = enmColor_Black;
  486.                         RotateRight(pParent->pRight);
  487.                     }
  488.                 }
  489.                 else if ((pNode == pParent->pRight)
  490.                  && (NULL != pBrother->pRight)
  491.                  && (enmColor_Red == pBrother->pRight->nColor))
  492.                 {
  493.                     if ((NULL == pBrother->pLeft)
  494.                             || (enmColor_Black == pBrother->pLeft->nColor))
  495.                     {
  496.                         pBrother->nColor = enmColor_Red;
  497.                         pBrother->pRight->nColor = enmColor_Black;
  498.                         RotateLeft(pParent->pLeft);
  499.                     }
  500.                 }
  501.                 //旋转后兄弟节点位置发生变化
  502.                 pBrother = Brother(pNode);
  503.             }

  504.             //case 6
  505.             pBrother->nColor = pParent->nColor;
  506.             pParent->nColor = enmColor_Black;
  507.             if (pNode == pParent->pLeft)
  508.             {
  509.                 if (NULL != pBrother->pRight)
  510.                 {
  511.                     pBrother->pRight->nColor = enmColor_Black;
  512.                 }
  513.                 RotateLeft(pParent);
  514.             }
  515.             else
  516.             {
  517.                 if (NULL != pBrother->pLeft)
  518.                 {
  519.                     pBrother->pLeft->nColor = enmColor_Black;
  520.                 }
  521.                 RotateRight(pParent);
  522.             }

  523.             break;
  524.         }

  525.         while((NULL != m_pRoot) && (NULL != m_pRoot->pParent))
  526.         {
  527.             m_pRoot = m_pRoot->pParent;
  528.         }
  529.     }

  530.     Node* Uncle(const Node *pNode)
  531.     {
  532.         Node *pParent = pNode->pParent;
  533.         if ((NULL == pParent) || (NULL == pParent->pParent))
  534.         {
  535.             return NULL;
  536.         }

  537.         Node *pGrandParent = pParent->pParent;
  538.         if (pParent == pGrandParent->pLeft)
  539.         {
  540.             return (NULL == pGrandParent->pRight) ? NULL : pGrandParent->pRight;
  541.         }

  542.         return (NULL == pGrandParent->pLeft) ? NULL : pGrandParent->pLeft;
  543.     }

  544.     Node* Brother(const Node *pNode)
  545.     {
  546.         if (NULL == pNode->pParent)
  547.         {
  548.             return NULL;
  549.         }

  550.         Node *pParent = pNode->pParent;
  551.         if (pNode == pParent->pLeft)
  552.         {
  553.             return (NULL == pParent->pRight) ? NULL : pParent->pRight;
  554.         }
  555.         return (NULL == pParent->pLeft) ? NULL : pParent->pLeft;
  556.     }


  557.     void RotateLeft(Node *pNode)
  558.     {
  559.         Node *pRSon = pNode->pRight;
  560.         
  561.         if (NULL != pNode->pParent)
  562.         {
  563.             Node *pParent = pNode->pParent;
  564.             (pNode == pParent->pLeft) ? pParent->pLeft = pNode->pRight : pParent->pRight = pNode->pRight;
  565.         }

  566.         pRSon->pParent = pNode->pParent;
  567.         pNode->pParent = pNode->pRight;
  568.         pNode->pRight = pRSon->pLeft;
  569.         pRSon->pLeft = pNode;

  570.         if (NULL != pNode->pRight)
  571.         {
  572.             pNode->pRight->pParent = pNode;
  573.         }
  574.     }

  575.     void RotateRight(Node *pNode)
  576.     {
  577.         Node *pLSon = pNode->pLeft;

  578.         if (NULL != pNode->pParent)
  579.         {
  580.             Node *pParent = pNode->pParent;
  581.             (pNode == pParent->pLeft) ? pParent->pLeft = pNode->pLeft: pParent->pRight = pNode->pLeft;
  582.         }

  583.         pLSon->pParent = pNode->pParent;
  584.         pNode->pParent = pNode->pLeft;
  585.         pNode->pLeft = pLSon->pRight;
  586.         pLSon->pRight = pNode;

  587.         if (NULL != pNode->pLeft)
  588.         {
  589.             pNode->pLeft->pParent = pNode;
  590.         }
  591.     }

  592.     bool SelfAndSonAllBlack(const Node *pNode)
  593.     {
  594.         if (enmColor_Black != pNode->nColor)
  595.         {
  596.             return false;
  597.         }

  598.         if ((NULL != pNode->pLeft)
  599.          && (enmColor_Black != pNode->pLeft->nColor))
  600.         {
  601.             return false;
  602.         }

  603.         if ((NULL != pNode->pRight)
  604.          && (enmColor_Black != pNode->pRight->nColor))
  605.         {
  606.             return false;
  607.         }

  608.         return true;
  609.     }

  610. protected:
  611.     Node                    *m_pRoot;
  612.     Node                    *m_pHead;
  613.     Node                    *m_pMin;

  614.     uint32_t                m_nSize;    
  615.     uint8_t                    *m_pBuffer;
  616. };

  617. #endif
下面是测试代码,在linux平台环境下测试通过

  1. #include <stdlib.h>
  2. #include <iostream>
  3. #include "frame_rbtree.h"
  4. using namespace std;

  5. #define COUT(x) \
  6.     do { cout << #x << "=" << x << endl; } while(false)

  7. typedef CRBTree<uint32_t, uint32_t, 16> RBTree;

  8. enum
  9. {
  10.     //enmKeySize = 512,
  11. };

  12. class A
  13. {
  14. public:
  15.     A()
  16.     {
  17.         COUT(__FUNCTION__);
  18.     }
  19.     ~A()
  20.     {
  21.         COUT(__FUNCTION__);
  22.     }
  23. };

  24. typedef CRBTree<uint32_t, uint32_t, 16> RBTree;

  25. typedef CRBTree<uint32_t, A, 16> ARBTree;

  26. int32_t main(const int32_t argc, const char** argv)
  27. {    
  28.     uint32_t enmKeySize = (uint32_t)atoi(argv[1]);
  29.     COUT(enmKeySize);

  30.     /*
  31.     A a;
  32.     ARBTree *Atree = new ARBTree();

  33.     for (uint32_t i = 0; i < enmKeySize; ++i)
  34.     {
  35.         Atree->Insert(i, a);
  36.     }

  37.     for (const ARBTree::Node *pNode = Atree->Begin(); NULL != pNode; pNode = Atree->Next(pNode))
  38.     {
  39.         COUT(pNode->nKey);
  40.     }

  41.     for (uint32_t i = 0; i < enmKeySize; ++i)
  42.     {
  43.         Atree->Delete(i);
  44.     }

  45.     Atree->Reserve(100);

  46.     COUT(Atree->GetSize());
  47.     COUT(Atree->GetCapacity());


  48.     delete Atree;
  49.     return 0;
  50.     */

  51.     uint32_t *arrKey = new uint32_t[enmKeySize];
  52.     for (uint32_t i = 0; i < enmKeySize; ++i)
  53.     {
  54.         arrKey[i] = i;
  55.     }

  56.     srand(time(NULL));
  57.     for (uint32_t i = 0; i < enmKeySize; ++i)
  58.     {
  59.         uint32_t nRand = rand() % enmKeySize;
  60.         uint32_t nTmp = arrKey[nRand];
  61.         arrKey[nRand] = arrKey[i];
  62.         arrKey[i] = nTmp;
  63.     }

  64.     RBTree *tree = new RBTree();
  65.     for (uint32_t i = 0; i < enmKeySize; ++i)
  66.     {
  67.         tree->Insert(arrKey[i], i);
  68.         //tree->Insert(i, i);
  69.     }

  70.     for (uint32_t i = 0; i < enmKeySize; i++)
  71.     {
  72.         tree->Delete(i);
  73.     }

  74.     for (uint32_t i = enmKeySize; i < enmKeySize * 2; ++i)
  75.     {
  76.         tree->Insert(i, i);
  77.     }

  78.     for (uint32_t i = 0; i < enmKeySize * 2; i += 10)
  79.     {
  80.         tree->Delete(i);
  81.     }

  82.     for (uint32_t i = 0; i < enmKeySize * 2; i += 10)
  83.     {
  84.         tree->Insert(i, i);
  85.     }

  86.     for (uint32_t i = 0; i < enmKeySize * 2; i += 10)
  87.     {
  88.         tree->Insert(0, 0);
  89.         tree->Insert(enmKeySize * 2, enmKeySize * 2);
  90.     }

  91.     for (const RBTree::Node *pNode = tree->Begin(); NULL != pNode; pNode = tree->Next(pNode))
  92.     {
  93.         printf("Key=%d, Value=%d\n", pNode->nKey, pNode->value);
  94.     }

  95.     COUT(tree->GetSize());
  96.     COUT(tree->GetCapacity());

  97.     return 0;
  98. }



阅读(1667) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~