单链表的c++实现

链表同样是一种线性表,但只是逻辑上的线性,地址空间并不连续,而是靠指针将各个节点连接起来,就像锁链一样,一环连一环。所以,需要定义一个节点类,用来存储数据和指向下一个节点的指针。为了简单,只定义了两个公有的成员变量。(双向链表则需定义两个指针,分别指向前驱和后继)

 1 #ifndef Node_hpp
 2 #define Node_hpp
 3 
 4 class Node
 5 {
 6 public:
 7     int Data;
 8     Node *NEXT;
 9 };
10 
11 #endif /* Node_hpp */

链表应该具有线性表的通用功能,所以定义函数为

 1 #ifndef LinkList_hpp
 2 #define LinkList_hpp
 3 #include "Node.hpp"
 4 
 5 class LinkList
 6 {
 7 public:
 8     LinkList();                     //建立链表(头节点)
 9     ~LinkList();                    //销毁链表
10     void ClearList();               //清空链表
11     bool ListEmpty();               //链表判空
12     int ListLength();               //链表长度
13     bool GetElem(int i,Node *pNode);//目标节点内容
14     int LocateElem(Node *pNode);    //目标节点位置
15     bool PriorElem(Node *pCurrentNode,Node *pPreNode);  //目标节点前驱‘
16     bool NextElem(Node *pCurrentNode,Node *pNextNode);  //目标节点后继
17     bool ListInsert(int i,Node *pNode);                 //插入节点
18     bool ListDelete(int i,Node *pNode);                 //删除节点
19     bool ListInsertHead(Node *pNode);                   //在链表开始处插入
20     bool ListInsertTail(Node *pNode);                   //在链表尾部插入
21     void ListTraverse();                                //遍历链表
22 private:
23     Node *_pList;
24     int _iListLen;
25 };
26 
27 #endif /* LinkList_hpp */

在建立链表的时候,并不需要规定链表的容量,因为有需要加入的内容,只需new一个节点类插入进去就可以了。

所以,构造函数只定义了一个头节点

1 LinkList::LinkList()
2 {
3     _pList=new Node;
4     _pList->Data=0;
5     _pList->NEXT=NULL;
6     _iListLen=0;
7 }

删除链表需要依次delete所有节点,而清空链表同样要delete掉除头节点外所有节点。通过while循环,只要当前节点的NEXT指向不为空,就像下一个节点移动,并删除当前节点。最后,不忘将当前节点置NULL。

 1 void LinkList::ClearList()
 2 {
 3     Node *currentNode=_pList->NEXT;
 4     while(currentNode->NEXT!=NULL)
 5     {
 6         Node *temp=currentNode->NEXT;
 7         delete currentNode;
 8         currentNode=temp;
 9     }
10     currentNode=NULL;
11     _iListLen=0;
12 }

销毁链表时,只需调用清空函数,最后销毁头节点

1 LinkList::~LinkList()
2 {
3     ClearList();
4     delete _pList;
5     _pList=NULL;
6 }

根据头节点的成员变量_iListLen,可以很容易得到判空函数和长度函数。因为链表没有满的状态,所以不需要定义判满

 1 bool LinkList::ListEmpty()
 2 {
 3     if(_iListLen==0)
 4     {
 5         return true;
 6     }
 7     else
 8     {
 9         return false;
10     }
11 }
12 
13 int LinkList::ListLength()
14 {
15     return _iListLen;
16 }

求目标节点数据和位置有相似的地方,都需要依次遍历,不同的是求数据的时候要先判断给的位置是否在规定范围内,再根据给的位置进行循环,而求位置则是直接从头遍历至尾,每次循环都要对比当前节点数据和目标节点数据是否相同(如果遍历至尾都没有相同的,则返回-1)

 1 bool LinkList::GetElem(int i,Node *pNode)
 2 {
 3     if(i<0||i>=_iListLen)
 4     {
 5         return false;
 6     }
 7     else
 8     {
 9         Node *currentNodt=_pList;
10         for(int k=0;k<=i;k++)
11         {
12             currentNodt=currentNodt->NEXT;
13         }
14         pNode->Data=currentNodt->Data;
15         return true;
16     }
17 }
18 
19 int LinkList::LocateElem(Node *pNode)
20 {
21     Node *currentNode=_pList;
22     int k=0;
23     while(currentNode->NEXT!=NULL)
24     {
25         currentNode=currentNode->NEXT;
26         if(currentNode->Data==pNode->Data)
27         {
28             return k;
29         }
30         k++;
31     }
32     return -1;
33 }

求前驱和后继的方式相似,定义两个相邻节点,遍历的同时移动,并与目标节点数据进行对比,如果求前驱,则用后面的节点对比,如果求后继,则用前面的节点对比

 1 bool LinkList::PriorElem(Node *pCurrentNode,Node *pPreNode)
 2 {
 3     Node *currentNode=_pList;
 4     Node *currentNodeBefore=NULL;
 5     while(currentNode->NEXT!=NULL)
 6     {
 7         currentNodeBefore=currentNode;
 8         currentNode=currentNode->NEXT;
 9         if(currentNode->Data==pCurrentNode->Data)
10         {
11             pPreNode->Data=currentNodeBefore->Data;
12             return true;
13         }
14     }
15     return false;
16 }
17 
18 bool LinkList::NextElem(Node *pCurrentNode,Node *pNextNode)
19 {
20     Node *currentNode=_pList;
21     Node *currentNodeBefore=NULL;
22     while(currentNode->NEXT!=NULL)
23     {
24         currentNodeBefore=currentNode;
25         currentNode=currentNode->NEXT;
26         if(currentNodeBefore->Data==pCurrentNode->Data)
27         {
28             pNextNode->Data=currentNode->Data;
29             return true;
30         }
31     }
32     return false;
33 }

插入与删除与根据位置求数据类似,需要先判断位置是否合法,再进行遍历。因为除头节点外,所有节点都只能由前驱节点的指针得到,所以先赋值插入节点的后继节点,再将插入节点赋值给前驱节点的后继。删除则只需要将目标节点的后继节点赋值给前驱节点的NEXT指针。

 1 bool LinkList::ListInsert(int i,Node *pNode)
 2 {
 3     if(i<0||i>=_iListLen)
 4     {
 5         return false;
 6     }
 7     else
 8     {
 9         Node *currentNode=_pList;
10         for(int k=0;k<i;k++)
11         {
12             currentNode=currentNode->NEXT;
13         }
14         Node *newNode=new Node;
15         newNode->Data=pNode->Data;
16         newNode->NEXT=currentNode->NEXT;
17         currentNode->NEXT=newNode;
18         _iListLen++;
19         return true;
20     }
21 }
22 
23 bool LinkList::ListDelete(int i,Node *pNode)
24 {
25     if(ListEmpty())
26     {
27         return false;
28     }
29     else
30     {
31         if(i<0||i>=_iListLen)
32         {
33             return false;
34         }
35         else
36         {
37             Node *currentNode=_pList;
38             Node *currentNodeBefore=NULL;
39             for(int k=0;k<=i;k++)
40             {
41                 currentNodeBefore=currentNode;
42                 currentNode=currentNode->NEXT;
43             }
44             currentNodeBefore->NEXT=currentNode->NEXT;
45             pNode->Data=currentNode->Data;
46             _iListLen--;
47             
48             delete currentNode;
49             currentNode=NULL;
50             return false;
51         }
52     }
53 }

在链表的头尾插入则是插入的特殊情况,一个是不需遍历,一个是需遍历所有

 1 bool LinkList::ListInsertHead(Node *pNode)
 2 {
 3     Node *temp=_pList->NEXT;
 4     Node *newNode=new Node;
 5     if(newNode==NULL)
 6     {
 7         return false;
 8     }
 9     else
10     {
11         newNode->Data=pNode->Data;
12         newNode->NEXT=temp;
13         _pList->NEXT=newNode;
14         _iListLen++;
15         return true;
16     }
17 }
18 
19 bool LinkList::ListInsertTail(Node *pNode)
20 {
21     Node *currentNode=_pList;
22     while(currentNode->NEXT!=NULL)
23     {
24         currentNode=currentNode->NEXT;
25     }
26     Node *newNode=new Node;
27     if(newNode==NULL)
28     {
29         return false;
30     }
31     else
32     {
33         newNode->Data=pNode->Data;
34         newNode->NEXT=NULL;
35         currentNode->NEXT=newNode;
36    
37         _iListLen++;
38         return true;
39     }
40 }

遍历链表结尾

 1 void LinkList::ListTraverse()
 2 {
 3     using namespace std;
 4     
 5     cout<<endl;
 6     Node *currentNode=_pList;
 7     while(currentNode->NEXT!=NULL)
 8     {
 9         currentNode=currentNode->NEXT;
10         cout<<currentNode->Data<<endl;
11     }
12     cout<<endl;
13 }

最后,因为涉及到好多循环,不可避免的有许多循环次数的问题,如果分析不清楚,可以通过在主函数中调用检验

 1 #include <iostream>
 2 #include "LinkList.hpp"
 3 
 4 int main(int argc, const char * argv[]) {
 5     // insert code here...
 6     using namespace std;
 7     
 8     LinkList *p=new LinkList;
 9     
10     Node *c=new Node;
11     
12     c->Data=3;
13     p->ListInsertHead(c);
14     c->Data=2;
15     p->ListInsertHead(c);
16     c->Data=5;
17     p->ListInsertTail(c);
18     c->Data=4;
19     p->ListInsert(2,c);
20     
21     p->ListTraverse();
22     
23     Node *d=new Node;
24     
25     p->GetElem(3, d);
26     cout<<d->Data<<endl;
27     p->PriorElem(c, d);
28     cout<<c->Data<<endl;
29     cout<<d->Data<<endl;
30     p->NextElem(c, d);
31     cout<<c->Data<<endl;
32     cout<<d->Data<<endl;
33     p->ListDelete(2, d);
34     cout<<d->Data<<endl;
35     
36     p->ListTraverse();
37     
38     delete d;
39     d=NULL;
40     
41     delete c;
42     c=NULL;
43     
44     delete p;
45     p=NULL;
46     
47     return 0;
48 }
49 #include <iostream>
50 #include "LinkList.hpp"
51 
52 int main(int argc, const char * argv[]) {
53     // insert code here...
54     using namespace std;
55     
56     LinkList *p=new LinkList;
57     
58     Node *c=new Node;
59     
60     c->Data=3;
61     p->ListInsertHead(c);
62     c->Data=2;
63     p->ListInsertHead(c);
64     c->Data=5;
65     p->ListInsertTail(c);
66     c->Data=4;
67     p->ListInsert(2,c);
68     
69     p->ListTraverse();
70     
71     Node *d=new Node;
72     
73     p->GetElem(3, d);
74     cout<<d->Data<<endl;
75     p->PriorElem(c, d);
76     cout<<c->Data<<endl;
77     cout<<d->Data<<endl;
78     p->NextElem(c, d);
79     cout<<c->Data<<endl;
80     cout<<d->Data<<endl;
81     p->ListDelete(2, d);
82     cout<<d->Data<<endl;
83     
84     p->ListTraverse();
85     
86     delete d;
87     d=NULL;
88     
89     delete c;
90     c=NULL;
91     
92     delete p;
93     p=NULL;
94     
95     return 0;
96 }

数据结构线性表基础部分告一段落

posted on 2017-02-05 12:06  京城妖  阅读(2636)  评论(0编辑  收藏  举报

导航