ListTemplates.h
上传用户:ghyvgy
上传日期:2009-05-26
资源大小:547k
文件大小:22k
源码类别:

其他游戏

开发平台:

Python

  1. /*
  2. s_p_oneil@hotmail.com
  3. Copyright (c) 2000, Sean O'Neil
  4. All rights reserved.
  5. Redistribution and use in source and binary forms, with or without
  6. modification, are permitted provided that the following conditions are met:
  7. * Redistributions of source code must retain the above copyright notice,
  8.   this list of conditions and the following disclaimer.
  9. * Redistributions in binary form must reproduce the above copyright notice,
  10.   this list of conditions and the following disclaimer in the documentation
  11.   and/or other materials provided with the distribution.
  12. * Neither the name of this project nor the names of its contributors
  13.   may be used to endorse or promote products derived from this software
  14.   without specific prior written permission.
  15. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  18. ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  19. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  20. CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  21. SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  22. INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  23. CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  24. ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  25. POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. #ifndef __ListTemplates_h__
  28. #define __ListTemplates_h__
  29. #include <fstream.h>
  30. template <class NODE, class INDEX> class CArray
  31. {
  32. protected:
  33. INDEX m_nElements; // The number of elements in the array
  34. INDEX m_nLockedElements; // The number of locked elements in the array
  35. unsigned char *m_pFlags; // An array of element status flags
  36. NODE *m_pBuffer; // The array of elements
  37. public:
  38. enum { Locked = 0x80, Dirty = 0x40 };
  39. // Constructor/destructor methods
  40. CArray(INDEX nElements=0)
  41. {
  42. m_nElements = 0;
  43. if(nElements)
  44. Init(nElements);
  45. }
  46. ~CArray() { Cleanup(); }
  47. // Init and Cleanup methods
  48. void Init(INDEX nElements)
  49. {
  50. Cleanup();
  51. m_nElements = nElements;
  52. m_nLockedElements = 0;
  53. m_pFlags = new unsigned char[m_nElements];
  54. memset(m_pFlags, 0, m_nElements);
  55. m_pBuffer = new NODE[m_nElements];
  56. }
  57. void Cleanup()
  58. {
  59. if(m_nElements)
  60. {
  61. delete []m_pBuffer;
  62. delete m_pFlags;
  63. m_nElements = 0;
  64. }
  65. }
  66. // Info methods
  67. INDEX GetElementCount() { return m_nElements; }
  68. INDEX GetElementSize() { return sizeof(NODE); }
  69. INDEX GetArraySize() { return GetElementCount() * GetElementSize(); }
  70. INDEX GetLockedElementCount() { return m_nLockedElements; }
  71. INDEX GetFreeElementCount() { return GetElementCount() - GetLockedElementCount(); }
  72. // Status flag methods
  73. unsigned char GetFlags(INDEX n) { return m_pFlags[n]; }
  74. void SetFlags(INDEX n, unsigned char nFlags) { m_pFlags[n] |= nFlags; }
  75. void ClearFlags(INDEX n, unsigned char nFlags) { m_pFlags[n] &= ~nFlags; }
  76. // Array manipulation methods
  77. NODE *GetBuffer() { return m_pBuffer; }
  78. NODE *operator[](INDEX n) { return &m_pBuffer[n]; }
  79. };
  80. template <class NODE, class INDEX> class CStackedArray : public CArray<NODE, INDEX>
  81. {
  82. protected:
  83. INDEX *m_pStack; // A stack of free element indices
  84. public:
  85. // Constructor/destructor methods
  86. CStackedArray(INDEX nElements=0)
  87. {
  88. m_nElements = 0;
  89. if(nElements)
  90. Init(nElements);
  91. }
  92. ~CStackedArray() { Cleanup(); }
  93. // Init and Cleanup methods
  94. void Init(INDEX nElements)
  95. {
  96. Cleanup();
  97. CArray<NODE, INDEX>::Init(nElements);
  98. m_pStack = new INDEX[m_nElements];
  99. for(INDEX i=0; i<m_nElements; i++)
  100. m_pStack[i] = i;
  101. }
  102. void Cleanup()
  103. {
  104. if(m_nElements)
  105. delete m_pStack;
  106. CArray<NODE, INDEX>::Cleanup();
  107. }
  108. // Array manipulation methods
  109. INDEX LockElement()
  110. {
  111. INDEX nElement = (INDEX)-1;
  112. if(m_nLockedElements < m_nElements)
  113. {
  114. nElement = m_pStack[m_nLockedElements++];
  115. m_pFlags[nElement] = Locked;
  116. }
  117. return nElement;
  118. }
  119. void UnlockElement(INDEX n)
  120. {
  121. m_pFlags[n] = 0;
  122. m_pStack[--m_nLockedElements] = n;
  123. }
  124. INDEX GetStackIndex(INDEX n) { return m_pStack[n]; }
  125. };
  126. template <class NODE, class INDEX> class CPackedArray : public CArray<NODE, INDEX>
  127. {
  128. protected:
  129. INDEX m_nLowestUnused; // The index of the lowest unused element in the array
  130. public:
  131. // Constructor/destructor methods
  132. CPackedArray(INDEX nElements=0)
  133. {
  134. m_nElements = 0;
  135. if(nElements)
  136. Init(nElements);
  137. }
  138. ~CPackedArray() { Cleanup(); }
  139. // Init and Cleanup methods
  140. void Init(INDEX nElements)
  141. {
  142. Cleanup();
  143. CArray<NODE, INDEX>::Init(nElements);
  144. m_nLowestUnused = 0;
  145. }
  146. void Cleanup()
  147. {
  148. }
  149. // Array manipulation methods
  150. INDEX LockElement()
  151. {
  152. INDEX nElement = (INDEX)-1;
  153. if(m_nLowestUnused < m_nElements)
  154. {
  155. nElement = m_nLowestUnused++;
  156. m_pFlags[nElement] |= Locked;
  157. m_nLockedElements++;
  158. while(m_nLowestUnused < m_nElements && (m_pFlags[m_nLowestUnused] & Locked))
  159. m_nLowestUnused++;
  160. }
  161. return nElement;
  162. }
  163. void UnlockElement(INDEX n)
  164. {
  165. m_pFlags[n] &= ~Locked;
  166. m_nLockedElements--;
  167. m_nLowestUnused = n < m_nLowestUnused ? n : m_nLowestUnused;
  168. }
  169. };
  170. /******************************************************************************
  171. * Class: CListNode
  172. *******************************************************************************
  173. * Deriving from this class turns your class into a node that can be used in a 
  174. * doubly-linked list. It was designed to work with CLinkedList (defined below)
  175. * in such a way that objects can insert and remove themselves from the list.
  176. * It is only templatized so it can use pointers of your class's type to keep
  177. * you from having to cast all returned pointers.
  178. Example:
  179. #define CMyObjectList CLinkedList<CMyObject>
  180. class CMyObject : public CListNode<CMyObject> { ... };
  181. ******************************************************************************/
  182. template <class A> class CListNode
  183. {
  184. public:
  185. A *m_pNext; // Points to next item in the list
  186. A *m_pPrevious; // Points to previous item in the list
  187. public:
  188. // Constructors/destructors
  189. CListNode() { m_pNext = m_pPrevious = NULL; }
  190. ~CListNode() { Remove(); }
  191. static void InitList(CListNode<A> &nHead, CListNode<A> &nTail)
  192. {
  193. nHead.m_pNext = (A *)&nTail;
  194. nTail.m_pPrevious = (A *)&nHead;
  195. }
  196. // Members to get the next and previous pointers (must use Insert/Remove members to set them)
  197. A *GetNext() { return m_pNext; }
  198. A *GetPrevious() { return m_pPrevious; }
  199. // Functions for searching the list, override these functions to use
  200. DWORD GetID() { return 0; }
  201. const char *GetName() { return ""; }
  202. void Write(ostream &os) { os.write((char *)this, sizeof(A)); }
  203. bool Read(istream &is)
  204. {
  205. is.read((char *)this, sizeof(A));
  206. m_pNext = m_pPrevious = NULL;
  207. return (!is ? false : true);
  208. }
  209. // Members to insert into, remove from, and check status in a list
  210. bool IsInList() { return (m_pNext != NULL && m_pPrevious != NULL); }
  211. void InsertBefore(A *pNode)
  212. {
  213. if(pNode && !IsInList())
  214. {
  215. m_pNext = pNode;
  216. m_pPrevious = pNode->m_pPrevious;
  217. pNode->m_pPrevious->m_pNext = (A *)this;
  218. pNode->m_pPrevious = (A *)this;
  219. }
  220. }
  221. void InsertAfter(A *pNode)
  222. {
  223. if(pNode && !IsInList())
  224. {
  225. m_pPrevious = pNode;
  226. m_pNext = pNode->m_pNext;
  227. pNode->m_pNext->m_pPrevious = (A *)this;
  228. pNode->m_pNext = (A *)this;
  229. }
  230. }
  231. void Remove()
  232. {
  233. if(m_pPrevious)
  234. m_pPrevious->m_pNext = m_pNext;
  235. if(m_pNext)
  236. m_pNext->m_pPrevious = m_pPrevious;
  237. m_pNext = m_pPrevious = NULL;
  238. }
  239. // Members to find items in the list by ID, name, or index
  240. A *FindID(DWORD dwID)
  241. {
  242. for(A *pNode = (A *)this; pNode->IsInList(); pNode=pNode->GetNext())
  243. {
  244. if(dwID == pNode->GetID())
  245. return pNode;
  246. }
  247. return NULL;
  248. }
  249. A *FindName(const char *pszName)
  250. {
  251. for(A *pNode = (A *)this; pNode->IsInList(); pNode=pNode->GetNext())
  252. {
  253. if(stricmp(pszName, pNode->GetName()) == 0)
  254. return pNode;
  255. }
  256. return NULL;
  257. }
  258. A *FindIndex(int nIndex)
  259. {
  260. A *pNode = (A *)this;
  261. for(int i=0; pNode->IsInList() && i<nIndex; i++)
  262. pNode = pNode->GetNext();
  263. return pNode->IsInList() ? pNode : NULL;
  264. }
  265. };
  266. /*******************************************************************************
  267. * Class: CLinkedList
  268. ********************************************************************************
  269. * This class implements a doubly-linked list that allows the objects within it
  270. * to insert and remove themselves without access to the actual list (to insert,
  271. * a pointer to an item already in the list is needed). To accomplish this,
  272. * static head and tail nodes must be kept instead of pointers, and no count
  273. * variable can used (because the objects have no way to update them). The head
  274. * and tail nodes point to each other when the list is empty. See CListNode above
  275. * for more information.
  276. Important Note:
  277. The static head and tail nodes mark the end of the list, not NULL. Use
  278. CListNode::IsInList() to see when you've reached the end, like this:
  279. for(CObject *p = list.GetHead(); p->IsInList(); p = p->GetNext()) { ... }
  280. *******************************************************************************/
  281. template <class A> class CLinkedList
  282. {
  283. protected:
  284. CListNode<A> m_nHead; // Points to head item
  285. CListNode<A> m_nTail; // Points to tail item
  286. public:
  287. // Constructors/destructors
  288. CLinkedList() { CListNode<A>::InitList(m_nHead, m_nTail); }
  289. ~CLinkedList() { RemoveAll(); }
  290. // Members to get the head and tail items of the list
  291. A *GetHead() { return m_nHead.GetNext(); }
  292. A *GetTail() { return m_nTail.GetPrevious(); }
  293. // Members to add items to the list
  294. void AddHead(A *p) { p->InsertAfter((A *)&m_nHead); }
  295. void AddTail(A *p) { p->InsertBefore((A *)&m_nTail); }
  296. void InsertBefore(A *p, A *pNode) { p->InsertBefore(pNode); }
  297. void InsertAfter(A *p, A *pNode) { p->InsertAfter(pNode); }
  298. // Members to remove items from the list
  299. A *Remove(A *p) { p->Remove(); return p; }
  300. A *RemoveHead() { return Remove(GetHead()); }
  301. A *RemoveTail() { return Remove(GetTail()); }
  302. void RemoveAll() { while(GetHead()->IsInList()) delete GetHead(); }
  303. // Members to get the size of the list
  304. bool IsEmpty() { return !GetHead()->IsInList(); }
  305. int GetCount()
  306. {
  307. register A *pNode = GetHead();
  308. for(int i=0; pNode->IsInList(); i++)
  309. pNode = pNode->GetNext();
  310. return i;
  311. }
  312. // Members to find items in the list by ID, name, or index
  313. A *FindID(DWORD dwID, A *pNode=NULL)
  314. {
  315. if(!pNode)
  316. pNode = GetHead();
  317. return pNode->FindID(dwID);
  318. }
  319. A *FindName(const char *pszName, A *pNode=NULL)
  320. {
  321. if(!pNode)
  322. pNode = GetHead();
  323. return pNode->FindName(pszName);
  324. }
  325. A *FindIndex(int nIndex, A *pNode=NULL)
  326. {
  327. if(!pNode)
  328. pNode = GetHead();
  329. return pNode->FindIndex(nIndex);
  330. }
  331. bool Read(istream &is)
  332. {
  333. int n;
  334. is.read((char *)&n, sizeof(int));
  335. if(!is)
  336. return false;
  337. for(int i=0; i<n; i++)
  338. {
  339. A *pNode = new A;
  340. if(!pNode->Read(is))
  341. return false;
  342. AddTail(pNode);
  343. }
  344. return true;
  345. }
  346. void Write(ostream &os)
  347. {
  348. int n = GetCount();
  349. os.write((char *)&n, sizeof(int));
  350. for(A *pNode=GetHead(); pNode->IsInList(); pNode=pNode->GetNext())
  351. pNode->Write(os);
  352. }
  353. };
  354. /******************************************************************************
  355. * Class: CTreeNode
  356. *******************************************************************************
  357. * Deriving from this class turns your class into a node to use in a tree of the
  358. * specified order. It is templatized simply so it can use pointers of your
  359. * class's type, keeping you from havig to cast pointers you get back.
  360. * Example:
  361. * class CMyObject : public CTreeNode<CMyObject, 4> { ... };
  362. ******************************************************************************/
  363. template <class A, int nOrder> class CTreeNode
  364. {
  365. protected:
  366. A *m_pParent;
  367. A *m_pChild[nOrder];
  368. public:
  369. CTreeNode(A *pParent=NULL)
  370. {
  371. m_pParent = pParent;
  372. for(register int i=0; i<nOrder; i++)
  373. m_pChild[i] = NULL;
  374. }
  375. ~CTreeNode()
  376. {
  377. for(register int i=0; i<nOrder; i++)
  378. {
  379. if(m_pParent && m_pParent->m_pChild[i] == this)
  380. m_pParent->SetChild(i, NULL);
  381. if(m_pChild[i])
  382. delete m_pChild[i];
  383. }
  384. }
  385. A *GetParent() { return m_pParent; }
  386. void SetParent(A *p) { m_pParent = p; }
  387. A *GetChild(int n) { return m_pChild[n]; }
  388. void SetChild(int n, A *p) { m_pChild[n] = p; }
  389. };
  390. /******************************************************************************
  391. * Class: CAVLTreeNode
  392. *******************************************************************************
  393. * Deriving from this class turns your class into a node to use in an AVL tree.
  394. * It was designed to work with CAVLTree (defined below).
  395. * Example:
  396. * #define CObjectTree CAVLTree<CObject>
  397. * class CObject : public CAVLTreeNode<CObject> { ... };
  398. ******************************************************************************/
  399. template <class A> class CAVLTreeNode : public CTreeNode<A, 2>
  400. {
  401. protected:
  402. short m_nBalance;
  403. protected:
  404. // Rotates pRoot left or right. Used to balance the tree. Returns true when the new root's parent needs to change its balance.
  405. // (To visualize what it's doing for either direction, replace nDirection with Left and nOtherDir with Right or vice-versa.)
  406. static bool RotateOnce(A *pRoot, int nDirection)
  407. {
  408. int nOtherDir = (nDirection == Left) ? Right : Left; // Get the other direction
  409. A *pParent = pRoot->m_pParent;
  410. int nSide = (pParent->m_pChild[Left] == pRoot) ? Left : Right;
  411. A *pNewRoot = pRoot->m_pChild[nOtherDir]; // Move nOtherDir child into root's current position (to move root in nDirection)
  412. pParent->m_pChild[nSide] = pNewRoot; // (Make parent point to new root)
  413. pNewRoot->m_pParent = pParent; // (Don't forget to change its parent)
  414. pRoot->m_pChild[nOtherDir] = pNewRoot->m_pChild[nDirection]; // Move new root's nDirection child to old root's nOtherDir
  415. if(pRoot->m_pChild[nOtherDir])
  416. pRoot->m_pChild[nOtherDir]->m_pParent = pRoot; // (Don't forget to change its parent)
  417. pNewRoot->m_pChild[nDirection] = pRoot; // Move old root down to the nDirection
  418. pRoot->m_pParent = pNewRoot; // (Don't forget to change its parent)
  419. // Update balances and return true if new root's parent's balance has changed
  420. bool bRetVal = (pNewRoot->m_nBalance == 0) ? false : true;
  421. pRoot->m_nBalance = -(nDirection ? ++(pNewRoot->m_nBalance) : --(pNewRoot->m_nBalance));
  422. return bRetVal;
  423. }
  424. // Rotates pRoot left or right twice (by rotating child in opposite direction first). Used to balance the tree. Returns true when the new root's parent needs to change its balance.
  425. // (To visualize what it's doing for either direction, replace nDirection with Left and nOtherDir with Right or vice-versa.)
  426. static bool RotateTwice(A *pRoot, int nDirection)
  427. {
  428. int nOtherDir = (nDirection == Left) ? Right : Left; // Get the other direction
  429. A *pParent = pRoot->m_pParent;
  430. int nSide = (pParent->m_pChild[Left] == pRoot) ? Left : Right;
  431. A *pNode = pRoot->m_pChild[nOtherDir]; // nOtherDir child doesn't move (but it gets a new parent)
  432. A *pNewRoot = pNode->m_pChild[nDirection]; // Move its nDirection child into root's current position (to move root in nDirection)
  433. pParent->m_pChild[nSide] = pNewRoot; // (Make parent point to new root)
  434. pNewRoot->m_pParent = pParent; // (Don't forget to change its parent)
  435. pRoot->m_pChild[nOtherDir] = pNewRoot->m_pChild[nDirection]; // Move new root's nDirection child to old root's nOtherDir
  436. if(pRoot->m_pChild[nOtherDir])
  437. pRoot->m_pChild[nOtherDir]->m_pParent = pRoot; // (Don't forget to change its parent)
  438. pNode->m_pChild[nDirection] = pNewRoot->m_pChild[nOtherDir]; // Move new root's nOtherDir child to the node that's not moving
  439. if(pNode->m_pChild[nDirection])
  440. pNode->m_pChild[nDirection]->m_pParent = pNode; // (Don't forget to change its parent)
  441. pNewRoot->m_pChild[nDirection] = pRoot; // Move old root down to the nDirection
  442. pRoot->m_pParent = pNewRoot; // (Don't forget to change its parent)
  443. pNewRoot->m_pChild[nOtherDir] = pNode; // Put the node that didn't move under new root
  444. pNode->m_pParent = pNewRoot; // (Don't forget to change its parent)
  445. // Update balances and return true
  446. pNewRoot->m_pChild[0]->m_nBalance = -max(pNewRoot->m_nBalance, 0);
  447. pNewRoot->m_pChild[1]->m_nBalance = -min(pNewRoot->m_nBalance, 0);
  448. pNewRoot->m_nBalance = 0;
  449. return true;
  450. }
  451. // Rebalances a single node. Returns true when the balance of pRoot's parent has been changed.
  452. static bool ReBalance(A *pRoot) 
  453. {
  454. bool bHeightChange = false;
  455. if(pRoot->m_nBalance < -1)
  456. bHeightChange = (pRoot->m_pChild[0]->m_nBalance == 1) ? RotateTwice(pRoot, Right) : RotateOnce(pRoot, Right);
  457. else if(pRoot->m_nBalance > 1)
  458. bHeightChange = (pRoot->m_pChild[1]->m_nBalance == -1) ? RotateTwice(pRoot, Left) : RotateOnce(pRoot, Left);
  459. return bHeightChange;
  460. }
  461. // Moves a locked node down in the tree down to where it can be safely deleted.
  462. static void MoveDown(A *pNode)
  463. {
  464. // Get pNode's parent and the side that points to pNode
  465. A *pParent = pNode->m_pParent;
  466. int nSide = (pParent->m_pChild[Left] == pNode) ? Left : Right;
  467. // Find the next item in the sort order (right one, then left all the way down)
  468. A *pSwap = pNode->m_pChild[Right];
  469. while(pSwap->m_pChild[Left])
  470. pSwap = pSwap->m_pChild[Left];
  471. // Swap the parent and right child pointers of the two nodes (must be handled differently if pNode is pSwap's parent)
  472. A *pTemp = pSwap->m_pChild[Right];
  473. if(pSwap->m_pParent == pNode)
  474. {
  475. pNode->m_pParent = pSwap;
  476. pSwap->m_pChild[Right] = pNode;
  477. }
  478. else
  479. {
  480. pNode->m_pParent = pSwap->m_pParent;
  481. pNode->m_pParent->m_pChild[(pNode->m_pParent->m_pChild[Left] == pSwap) ? Left : Right] = pNode;
  482. pSwap->m_pChild[Right] = pNode->m_pChild[Right];
  483. pSwap->m_pChild[Right]->m_pParent = pSwap;
  484. }
  485. pNode->m_pChild[Right] = pTemp;
  486. if(pNode->m_pChild[Right])
  487. pNode->m_pChild[Right]->m_pParent = pNode;
  488. pSwap->m_pParent = pParent;
  489. pParent->m_pChild[nSide] = pSwap;
  490. // Swap the left child of the two nodes (easy because pNode's left child is never NULL and pSwap's left child is always NULL)
  491. pSwap->m_pChild[Left] = pNode->m_pChild[Left];
  492. pSwap->m_pChild[Left]->m_pParent = pSwap;
  493. pNode->m_pChild[Left] = NULL;
  494. // Swap the balance factors of the two nodes
  495. short nTemp = pNode->m_nBalance;
  496. pNode->m_nBalance = pSwap->m_nBalance;
  497. pSwap->m_nBalance = nTemp;
  498. }
  499. public:
  500. enum { Left, Right };
  501. CAVLTreeNode() : CTreeNode<A, 2>() { m_nBalance = 0; }
  502. bool IsInTree() { return (m_pParent != NULL); }
  503. int GetBalance() { return m_nBalance; }
  504. // Inserts the current node into an AVL tree which has a root of pRoot
  505. // pRoot is actually a placeholder node for the root, the tree actually starts in its left subtree
  506. // Returns true for success, false for failure
  507. bool Insert(A *pRoot)
  508. {
  509. A *pParent = pRoot;
  510. A *pNode = pRoot->m_pChild[Left];
  511. int nCompare = -1;
  512. while(pNode)
  513. {
  514. nCompare = pNode->Compare((A *)this);
  515. if(!nCompare)
  516. return false;
  517. pParent = pNode;
  518. pNode = pNode->m_pChild[(nCompare > 0) ? Right : Left];
  519. }
  520. pNode = (A *)this;
  521. pNode->m_pParent = pParent;
  522. pParent->m_pChild[(nCompare > 0) ? Right : Left] = pNode;
  523. while(pParent->IsInTree())
  524. {
  525. pNode = pParent;
  526. pParent = pNode->m_pParent;
  527. pNode->m_nBalance += nCompare;
  528. nCompare = (pParent->m_pChild[Left] == pNode) ? -1 : 1;
  529. if(!pNode->m_nBalance || ReBalance(pNode))
  530. break;
  531. }
  532. return true;
  533. }
  534. // Removes the current node from an AVL tree
  535. // Returns true for success, false for failure
  536. bool Remove()
  537. {
  538. if(m_pChild[Left] && m_pChild[Right])
  539. MoveDown((A *)this);
  540. int nDirection = (m_pChild[Left] != NULL) ? Left : Right;
  541. A *pParent = m_pParent;
  542. A *pNode = m_pChild[nDirection];
  543. m_pParent = NULL;
  544. m_pChild[nDirection] = NULL;
  545. int nCompare = (pParent->m_pChild[Left] == (A *)this) ? -1 : 1;
  546. pParent->m_pChild[(nCompare > 0) ? Right : Left] = pNode;
  547. if(pNode)
  548. pNode->m_pParent = pParent;
  549. while(pParent->IsInTree())
  550. {
  551. pNode = pParent;
  552. pParent = pNode->m_pParent;
  553. pNode->m_nBalance -= nCompare;
  554. nCompare = (pParent->m_pChild[Left] == pNode) ? -1 : 1;
  555. if(pNode->m_nBalance && !ReBalance(pNode))
  556. break;
  557. }
  558. return true;
  559. }
  560. };
  561. /*******************************************************************************
  562. * Class: CAVLTree
  563. ********************************************************************************
  564. * This class implements an AVL tree.
  565. *******************************************************************************/
  566. template <class A, class KeyType> class CAVLTree
  567. {
  568. protected:
  569. CAVLTreeNode<A> m_nRoot;
  570. int m_nCount;
  571. void RecursiveCount(A *pNode)
  572. {
  573. if(!pNode)
  574. return;
  575. m_nCount++;
  576. RecursiveCount(pNode->GetChild(0));
  577. RecursiveCount(pNode->GetChild(1));
  578. }
  579. public:
  580. CAVLTree() { m_nCount = 0; }
  581. bool IsEmpty() { return (GetRoot() == NULL); }
  582. A *GetRoot() { return m_nRoot.GetChild(0); }
  583. bool Insert(A *pNode) { return pNode->Insert((A *)&m_nRoot); }
  584. bool Remove(A *pNode) { return pNode->Remove(); }
  585. int GetCount()
  586. {
  587. m_nCount = 0;
  588. RecursiveCount(GetRoot());
  589. return m_nCount;
  590. }
  591. int GetMaxDepth()
  592. {
  593. A *pNode = GetRoot();
  594. for(int nDepth=0; pNode; nDepth++)
  595. pNode = pNode->GetChild(pNode->GetBalance() <= 0 ? 0 : 1);
  596. return nDepth;
  597. }
  598. A *FindKey(KeyType tKey)
  599. {
  600. int nCompare;
  601. A *pNode = GetRoot();
  602. while(pNode && (nCompare = pNode->Compare(tKey)) != 0)
  603. pNode = (nCompare > 0) ? pNode->GetChild(1) : pNode->GetChild(0);
  604. return pNode;
  605. }
  606. A *Remove(KeyType tKey)
  607. {
  608. A *pNode = FindKey(tKey);
  609. if(pNode)
  610. pNode->Remove();
  611. return pNode;
  612. }
  613. };
  614. #endif // __ListTemplates_h__