严蔚敏老师的数据结构分析一书中,都是采用带头结点的链表,可能读者一时间还不知道是什么意思:首先看一段伪代码:
L是链表的头结点
L=(LinkList)malloc(sizeof(LNode));
L->next=NULL;
链表的头指针也是一个结点,尽管这是一个空的结点,只是说明这个结点并没有携带任何有效的参数。
而我的实现当中确实没有分配一个结点,而只是一个指针,指向第一个元素。
typedef struct SNode{ int nData; SNode* pNextNode; }SNode,pSNode; class CList { private: SNode* m_pListHeader; SNode* m_pListTail; public: CList(); ~CList(); void InsertList(int a); void Merge(CList* p1,CList *p2); void Display(); };
void CList::InsertList(int a){ SNode* pNewNode=new SNode; pNewNode->nData=a; pNewNode->pNextNode=NULL; if(NULL==m_pListHeader) { m_pListHeader=m_pListTail=pNewNode; } else { m_pListTail->pNextNode=pNewNode; m_pListTail=pNewNode; } }
从插入结点就可以了解到我并没有申请头结点,而是将一个元素的指针赋值给了头指针。
两种方法有什么不同的地方,对于操作者来说应该如何区分:
这i里涉及到我们对查询的当前结点不感兴趣,而只是对当前结点的前一个结点感兴趣的时候,问题来了,主要是删除结点的时候会比较麻烦:
int CStudentLink::DelStudentNode(int id){ //链表为空,返回 if(NULL==m_pStudentLinkHeader) { return -1; } //尝试查询第一个元素 if(id==m_pStudentLinkHeader->nID) { cout<<"delete ID:"<<m_pStudentLinkHeader->nID<<endl; delete m_pStudentLinkHeader; m_pStudentLinkHeader=m_pStudentLinkHeader->pNextNode; //m_pStudentLinkHeader==NULL;ERROR:后面可能还有元素 return 0; } //如果下一个节点为空,返回 if(NULL==m_pStudentLinkHeader->pNextNode) { return -2; } //如果第二个元素不为空,遍历第二元素 SStudentNode* pTmpNode=m_pStudentLinkHeader; SStudentNode* pNextTmp=pTmpNode->pNextNode; while(NULL!=pNextTmp) { if(id==pNextTmp->nID) { pTmpNode->pNextNode=pNextTmp->pNextNode; cout<<"delete ID:"<<pNextTmp->nID<<endl; delete pNextTmp; pNextTmp=NULL; return 0; } pTmpNode=pNextTmp; pNextTmp=pNextTmp->pNextNode; } cout<<"Travser all node ,but not match"<<endl; return -3; }
为了实现学生结点的删除,上面的代码不少了,如果我们是使用创建一个空的头结点的方式,应该会非常的轻松。
SNode* pTmp=m_pStudentLinkHeader; while(NULL!=pTmp->pNextNode) { if(id==pTmp->pNextNode->nID) { SNode* p=pTmp->pNextNode; pTmp->pNextNode=pTmp->pNextNode->pNextNode; delete p; return 0; } pTmp=pTmp->pNextNode; } return -1;
时间: 2024-10-23 07:07:24