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++
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;
|
|
|