////////////////////////////////////////////////////////////////////////////// //文件 TList.h //主要功能: // 链表模块类 ///////////////////////////////////////////////////////////////////////////// #pragma once #ifdef _GDF_QT #include "GBase/QGBase/BaseDef.h" #define ENSURE Q_ASSERT #endif namespace NSet { #ifndef _WIN64 typedef long DF_LONG; //定义32位整型 #else typedef __int64 DF_LONG; //定义64位整型 #endif template class TList { public: // Construction TList(int nBlockSize = 10); TList(TList& pNewList, int nBlockSize = 10); virtual ~TList(); // Attributes (head and tail) // count of elements DF_LONG GetCount() const; DF_LONG GetSize() const; bool IsEmpty() const; // peek at head or tail T& GetHead(); const T& GetHead() const; T& GetTail(); const T& GetTail() const; // Operations // get head or tail (and remove it) - don't call on empty list! T RemoveHead(); T RemoveTail(); // add before head or after tail POSITION AddHead(T newElement); POSITION AddTail(T newElement); // add another list of elements before head or after tail void AddHead(TList* pNewList); void AddTail(TList* pNewList); // remove all elements void RemoveAll(bool bErasing = true); // iteration POSITION GetHeadPosition() const; POSITION GetTailPosition() const; T& GetNext(POSITION& rPosition); // return *Position++ const T& GetNext(POSITION& rPosition) const; // return *Position++ T& GetPrev(POSITION& rPosition); // return *Position-- const T& GetPrev(POSITION& rPosition) const; // return *Position-- // getting/modifying an element at a given position T& GetAt(POSITION position); const T& GetAt(POSITION position) const; void SetAt(POSITION pos, T newElement); void RemoveAt(POSITION position); bool Swap(POSITION pos1, POSITION pos2); //swap two position element void Reversal(); // inserting before or after a given position POSITION InsertBefore(POSITION position, T newElement); POSITION InsertAfter(POSITION position, T newElement); // helper functions (note: O(n) speed) POSITION Find(T searchValue, POSITION startAfter = NULL) const; // defaults to starting at the HEAD // return NULL if not found POSITION FindIndex(INT_PTR nIndex) const; // get the 'nIndex'th element (may return NULL) // Implementation protected: struct TNode { TNode * pNext; TNode * pPrev; T data; }; struct CBlock // warning variable length structure { CBlock* pNext; #ifndef _WIN64 #if (_AFX_PACKING >= 8) DWORD dwReserved[1]; // align on 8 byte boundary #endif #endif // BYTE data[maxNum*elementSize]; void* data() { return this+1; } static CBlock* Create(CBlock*& pHead, DF_LONG nMax, DF_LONG cbElement) { CBlock* p = (CBlock*) new BYTE[sizeof(CBlock) + nMax * cbElement]; // may throw exception p->pNext = (CBlock*)pHead; pHead = p; // change head (adds in reverse order for simplicity) return p; } // like 'calloc' but no zero fill // may throw memory exceptions void FreeDataChain() // free this one and links { CBlock* p = this; while (p != NULL) { BYTE* bytes = (BYTE*) p; CBlock* pNext = p->pNext; delete[] bytes; p = pNext; } } }; protected: TNode* m_pNodeHead; TNode* m_pNodeTail; TNode* m_pNodeFree; CBlock* m_pBlocks; DF_LONG m_nBlockSize; DF_LONG m_nCount; TNode* NewNode(TNode*, TNode*); void FreeNode(TNode*); //public: // // local typedefs for class templates // typedef T BASE_TYPE; // typedef T BASE_ARG_TYPE; }; //类实现 template TList::TList(int nBlockSize /*= 10*/) { m_nBlockSize = nBlockSize; m_nCount = 0; m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL; m_pBlocks = NULL; } template TList::TList(TList& pNewList, int nBlockSize /*= 10*/) { m_nBlockSize = nBlockSize; m_nCount = 0; m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL; m_pBlocks = NULL; // add a list of same elements AddTail(&pNewList); } template TList::~TList() { RemoveAll(); } template DF_LONG TList::GetCount() const { return m_nCount; } template DF_LONG TList::GetSize() const { return m_nCount; } template bool TList::IsEmpty() const { return m_nCount == 0; } template T& TList::GetHead() { //ENSURE(m_pNodeHead != NULL); return m_pNodeHead->data; } template const T& TList::GetHead() const { ENSURE(m_pNodeHead != NULL); return m_pNodeHead->data; } template T& TList::GetTail() { ENSURE(m_pNodeTail != NULL); return m_pNodeTail->data; } template const T& TList::GetTail() const { ENSURE(m_pNodeTail != NULL); return m_pNodeTail->data; } template T TList::RemoveHead() { #ifndef _GDF_QT ENSURE(m_pNodeHead != NULL); // don't call on empty list !!! ASSERT(AfxIsValidAddress(m_pNodeHead, sizeof(TNode))); #endif TNode* pOldNode = m_pNodeHead; T returnValue = pOldNode->data; m_pNodeHead = pOldNode->pNext; if (m_pNodeHead != NULL) m_pNodeHead->pPrev = NULL; else m_pNodeTail = NULL; FreeNode(pOldNode); return returnValue; } template T TList::RemoveTail() { #ifndef _GDF_QT ENSURE(m_pNodeTail != NULL); // don't call on empty list !!! ASSERT(AfxIsValidAddress(m_pNodeTail, sizeof(TNode))); #endif TNode* pOldNode = m_pNodeTail; T returnValue = pOldNode->data; m_pNodeTail = pOldNode->pPrev; if (m_pNodeTail != NULL) m_pNodeTail->pNext = NULL; else m_pNodeHead = NULL; FreeNode(pOldNode); return returnValue; } template POSITION TList::AddHead(T newElement) { TNode* pNewNode = NewNode(NULL, m_pNodeHead); pNewNode->data = newElement; if (m_pNodeHead != NULL) m_pNodeHead->pPrev = pNewNode; else m_pNodeTail = pNewNode; m_pNodeHead = pNewNode; return (POSITION) pNewNode; } template POSITION TList::AddTail(T newElement) { TNode* pNewNode = NewNode(m_pNodeTail, NULL); pNewNode->data = newElement; if (m_pNodeTail != NULL) m_pNodeTail->pNext = pNewNode; else m_pNodeHead = pNewNode; m_pNodeTail = pNewNode; return (POSITION) pNewNode; } template void TList::AddHead(TList* pNewList) { //ENSURE(pNewList != NULL); // add a list of same elements to head (maintain order) POSITION pos = pNewList->GetTailPosition(); while (pos != NULL) AddHead(pNewList->GetPrev(pos)); } template void TList::AddTail(TList* pNewList) { //ENSURE(pNewList != NULL); // add a list of same elements POSITION pos = pNewList->GetHeadPosition(); while (pos != NULL) AddTail(pNewList->GetNext(pos)); } template void TList::RemoveAll(bool bErasing /*= true*/) { //// destroy elements //TNode* pNode; //for (pNode = m_pNodeHead; pNode != NULL; pNode = pNode->pNext) // pNode->data.~T(); if(bErasing) m_pBlocks->FreeDataChain(); m_nCount = 0; m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL; m_pBlocks = NULL; } template void TList::Reversal() { if(GetCount() <= 1) return; int num = GetCount()/2; POSITION ptHead, ptTail; POSITION posHead = GetHeadPosition(); POSITION posTail = GetTailPosition(); for(int i=0; i bool TList::Swap(POSITION pos1, POSITION pos2) { if(pos1==pos2 || pos1==NULL || pos2==NULL) return false; TNode* pNode1 = (TNode*) pos1; TNode* pNode2 = (TNode*) pos2; T pTempData = pNode1->data; pNode1->data = pNode2->data; pNode2->data = pTempData; /*TNode* pTemp; pTemp = pNode1->pPrev; pNode1->pPrev = pNode2->pPrev; pNode2->pPrev = pTemp; pTemp = pNode1->pNext; pNode1->pNext = pNode2->pNext; pNode2->pNext = pTemp; if(pNode1->pPrev == pNode1) pNode1->pPrev = pNode2; if(pNode1->pNext == pNode1) pNode1->pNext = pNode2; if(pNode2->pPrev == pNode2) pNode2->pPrev = pNode1; if(pNode2->pNext == pNode2) pNode2->pNext = pNode1;*/ return true; } template POSITION TList::GetHeadPosition() const { return (POSITION) m_pNodeHead; } template POSITION TList::GetTailPosition() const { return (POSITION) m_pNodeTail; } template T& TList::GetNext(POSITION& rPosition) // return *Position++ { TNode* pNode = (TNode*) rPosition; #ifndef _GDF_QT ASSERT(AfxIsValidAddress(pNode, sizeof(TNode))); if( pNode == NULL ) AfxThrowInvalidArgException(); #endif rPosition = (POSITION) pNode->pNext; return pNode->data; } template const T& TList::GetNext(POSITION& rPosition) const // return *Position++ { TNode* pNode = (TNode*) rPosition; #ifndef _GDF_QT ASSERT(AfxIsValidAddress(pNode, sizeof(TNode))); if( pNode == NULL ) AfxThrowInvalidArgException(); #endif rPosition = (POSITION) pNode->pNext; return pNode->data; } template T& TList::GetPrev(POSITION& rPosition) // return *Position-- { TNode* pNode = (TNode*) rPosition; #ifndef _GDF_QT ASSERT(AfxIsValidAddress(pNode, sizeof(TNode))); if( pNode == NULL ) AfxThrowInvalidArgException(); #endif rPosition = (POSITION) pNode->pPrev; return pNode->data; } template const T& TList::GetPrev(POSITION& rPosition) const // return *Position-- { TNode* pNode = (TNode*) rPosition; #ifndef _GDF_QT ASSERT(AfxIsValidAddress(pNode, sizeof(TNode))); if( pNode == NULL ) AfxThrowInvalidArgException(); #endif rPosition = (POSITION) pNode->pPrev; return pNode->data; } template T& TList::GetAt(POSITION position) { TNode* pNode = (TNode*) position; #ifndef _GDF_QT ASSERT(AfxIsValidAddress(pNode, sizeof(TNode))); if( pNode == NULL ) AfxThrowInvalidArgException(); #endif return pNode->data; } template const T& TList::GetAt(POSITION position) const { TNode* pNode = (TNode*) position; #ifndef _GDF_QT ASSERT(AfxIsValidAddress(pNode, sizeof(TNode))); if( pNode == NULL ) AfxThrowInvalidArgException(); #endif return pNode->data; } template void TList::SetAt(POSITION pos, T newElement) { TNode* pNode = (TNode*) pos; #ifndef _GDF_QT ASSERT(AfxIsValidAddress(pNode, sizeof(TNode))); if( pNode == NULL ) AfxThrowInvalidArgException(); #endif pNode->data = newElement; } template void TList::RemoveAt(POSITION position) { TNode* pOldNode = (TNode*) position; #ifndef _GDF_QT ASSERT(AfxIsValidAddress(pOldNode, sizeof(TNode))); #endif // remove pOldNode from list if (pOldNode == m_pNodeHead) { m_pNodeHead = pOldNode->pNext; } else { #ifndef _GDF_QT ASSERT(AfxIsValidAddress(pOldNode->pPrev, sizeof(TNode))); #endif pOldNode->pPrev->pNext = pOldNode->pNext; } if (pOldNode == m_pNodeTail) { m_pNodeTail = pOldNode->pPrev; } else { #ifndef _GDF_QT ASSERT(AfxIsValidAddress(pOldNode->pNext, sizeof(TNode))); #endif pOldNode->pNext->pPrev = pOldNode->pPrev; } FreeNode(pOldNode); } template POSITION TList::InsertBefore(POSITION position, T newElement) { if (position == NULL) return AddHead(newElement); // insert before nothing -> head of the list // Insert it before position TNode* pOldNode = (TNode*) position; TNode* pNewNode = NewNode(pOldNode->pPrev, pOldNode); pNewNode->data = newElement; if (pOldNode->pPrev != NULL) { #ifndef _GDF_QT ASSERT(AfxIsValidAddress(pOldNode->pPrev, sizeof(TNode))); #endif pOldNode->pPrev->pNext = pNewNode; } else { #ifndef _GDF_QT ASSERT(pOldNode == m_pNodeHead); #endif m_pNodeHead = pNewNode; } pOldNode->pPrev = pNewNode; return (POSITION) pNewNode; } template POSITION TList::InsertAfter(POSITION position, T newElement) { if (position == NULL) return AddTail(newElement); // insert after nothing -> tail of the list // Insert it before position TNode* pOldNode = (TNode*) position; #ifndef _GDF_QT ASSERT(AfxIsValidAddress(pOldNode, sizeof(TNode))); #endif TNode* pNewNode = NewNode(pOldNode, pOldNode->pNext); pNewNode->data = newElement; if (pOldNode->pNext != NULL) { #ifndef _GDF_QT ASSERT(AfxIsValidAddress(pOldNode->pNext, sizeof(TNode))); #endif pOldNode->pNext->pPrev = pNewNode; } else { #ifndef _GDF_QT ASSERT(pOldNode == m_pNodeTail); #endif m_pNodeTail = pNewNode; } pOldNode->pNext = pNewNode; return (POSITION) pNewNode; } template POSITION TList::Find(T searchValue, POSITION startAfter /*= NULL*/) const { TNode* pNode = (TNode*) startAfter; if (pNode == NULL) { pNode = m_pNodeHead; // start at head } else { #ifndef _GDF_QT ASSERT(AfxIsValidAddress(pNode, sizeof(TNode))); #endif pNode = pNode->pNext; // start after the one specified } for (; pNode != NULL; pNode = pNode->pNext) if (pNode->data == searchValue) return (POSITION)pNode; return NULL; } template POSITION TList::FindIndex(INT_PTR nIndex) const { if (nIndex >= m_nCount || nIndex < 0) return NULL; // went too far TNode* pNode = m_pNodeHead; while (nIndex--) { #ifndef _GDF_QT ASSERT(AfxIsValidAddress(pNode, sizeof(TNode))); #endif pNode = pNode->pNext; } return (POSITION) pNode; } template typename TList::TNode* TList::NewNode(TNode*pPrev , TNode* pNext) { if (m_pNodeFree == NULL) { if(m_nBlockSize<=0) m_nBlockSize = 10; CBlock* pNewBlock = CBlock::Create(m_pBlocks, m_nBlockSize, sizeof(TNode)); // chain them into free list TNode* pNode = (TNode*) pNewBlock->data(); pNode += m_nBlockSize - 1; for(DF_LONG i=m_nBlockSize-1; i>=0; i--,pNode--) { pNode->pNext = m_pNodeFree; m_pNodeFree = pNode; } } TNode *pNode = m_pNodeFree; m_pNodeFree = m_pNodeFree->pNext; pNode->pPrev = pPrev; pNode->pNext = pNext; m_nCount++; #pragma push_macro("new") #undef new ::new( (void*)( &pNode->data ) ) T; #pragma pop_macro("new") return pNode; } template void TList::FreeNode(TNode* pNode) { pNode->pNext = m_pNodeFree; m_pNodeFree = pNode; m_nCount--; // if no more elements, cleanup completely if (m_nCount == 0) RemoveAll(); } #undef DF_LONG //取消类型定义 }; using namespace NSet;