You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

673 lines
14 KiB
C++

//////////////////////////////////////////////////////////////////////////////
//文件 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 T>
class TList
{
public:
// Construction
TList(int nBlockSize = 10);
TList(TList<T>& 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<T>* pNewList);
void AddTail(TList<T>* 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 <class T>
TList<T>::TList(int nBlockSize /*= 10*/)
{
m_nBlockSize = nBlockSize;
m_nCount = 0;
m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL;
m_pBlocks = NULL;
}
template <class T>
TList<T>::TList(TList<T>& 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 <class T>
TList<T>::~TList()
{
RemoveAll();
}
template <class T>
DF_LONG TList<T>::GetCount() const
{
return m_nCount;
}
template <class T>
DF_LONG TList<T>::GetSize() const
{
return m_nCount;
}
template <class T>
bool TList<T>::IsEmpty() const
{
return m_nCount == 0;
}
template <class T>
T& TList<T>::GetHead()
{
//ENSURE(m_pNodeHead != NULL);
return m_pNodeHead->data;
}
template <class T>
const T& TList<T>::GetHead() const
{
ENSURE(m_pNodeHead != NULL);
return m_pNodeHead->data;
}
template <class T>
T& TList<T>::GetTail()
{
ENSURE(m_pNodeTail != NULL);
return m_pNodeTail->data;
}
template <class T>
const T& TList<T>::GetTail() const
{
ENSURE(m_pNodeTail != NULL);
return m_pNodeTail->data;
}
template <class T>
T TList<T>::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 <class T>
T TList<T>::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 <class T>
POSITION TList<T>::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 <class T>
POSITION TList<T>::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 <class T>
void TList<T>::AddHead(TList<T>* 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 <class T>
void TList<T>::AddTail(TList<T>* pNewList)
{
//ENSURE(pNewList != NULL);
// add a list of same elements
POSITION pos = pNewList->GetHeadPosition();
while (pos != NULL)
AddTail(pNewList->GetNext(pos));
}
template <class T>
void TList<T>::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 <class T>
void TList<T>::Reversal()
{
if(GetCount() <= 1)
return;
int num = GetCount()/2;
POSITION ptHead, ptTail;
POSITION posHead = GetHeadPosition();
POSITION posTail = GetTailPosition();
for(int i=0; i<num; i++)
{
ptHead = posHead;
ptTail = posTail;
GetNext(posHead);
GetPrev(posTail);
Swap(ptHead, ptTail);
//if(posHead == posTail)
// break;
//if(posHead == NULL || posTail == NULL)
// break;
}
}
//swap two position element
template <class T>
bool TList<T>::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 <class T>
POSITION TList<T>::GetHeadPosition() const
{
return (POSITION) m_pNodeHead;
}
template <class T>
POSITION TList<T>::GetTailPosition() const
{
return (POSITION) m_pNodeTail;
}
template <class T>
T& TList<T>::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 <class T>
const T& TList<T>::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 <class T>
T& TList<T>::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 <class T>
const T& TList<T>::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 <class T>
T& TList<T>::GetAt(POSITION position)
{
TNode* pNode = (TNode*) position;
#ifndef _GDF_QT
ASSERT(AfxIsValidAddress(pNode, sizeof(TNode)));
if( pNode == NULL )
AfxThrowInvalidArgException();
#endif
return pNode->data;
}
template <class T>
const T& TList<T>::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 <class T>
void TList<T>::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 <class T>
void TList<T>::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 <class T>
POSITION TList<T>::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 <class T>
POSITION TList<T>::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 <class T>
POSITION TList<T>::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 <class T>
POSITION TList<T>::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 <class T>
typename TList<T>::TNode* TList<T>::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 <class T>
void TList<T>::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;