第二十二课 单链表的具体实现

Posted wanmeishenghuo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第二十二课 单链表的具体实现相关的知识,希望对你有一定的参考价值。

本节目标:

技术分享图片

技术分享图片

技术分享图片

添加LinkList.h文件:

  1 #ifndef LINKLIST_H
  2 #define LINKLIST_H
  3 
  4 #include "List.h"
  5 #include "Exception.h"
  6 
  7 namespace DTLib
  8 {
  9 
 10 template < typename T >
 11 class LinkList : public List<T>
 12 {
 13 protected:
 14     struct Node : public Object
 15     {
 16         T value;
 17         Node* next;
 18     };
 19 
 20     mutable Node m_header;
 21     int m_length;
 22 public:
 23     LinkList()
 24     {
 25         m_header.next = NULL;
 26         m_length = 0;
 27     }
 28 
 29     bool insert(const T& e)
 30     {
 31         return insert(m_length, e);
 32     }
 33 
 34     bool insert(int i, const T& e)
 35     {
 36         bool ret = ((0 <= i) && (i <= m_length));
 37 
 38         if( ret )
 39         {
 40             Node* node = new Node();
 41 
 42             if( node != NULL )
 43             {
 44                 Node* current = &m_header;
 45 
 46                 for(int p=0; p<i; p++)
 47                 {
 48                     current = current->next;
 49                 }
 50 
 51                 node->value = e;
 52                 node->next = current->next;
 53                 current->next = node;
 54 
 55                 m_length++;
 56             }
 57             else
 58             {
 59                 THROW_EXCEPTION(NoEnoughMemoryException, "No memery to insert new element...");
 60             }
 61         }
 62 
 63         return ret;
 64     }
 65 
 66     bool remove(int i)
 67     {
 68         bool ret = ((0 <= i) && (i < m_length));
 69 
 70         if( ret )
 71         {
 72             Node* current = &m_header;
 73 
 74             for(int p=0; p<i; p++)
 75             {
 76                 current = current->next;
 77             }
 78 
 79             Node* toDel = current->next;
 80 
 81             current->next = toDel->next;
 82 
 83             delete toDel;
 84 
 85             m_length--;
 86         }
 87 
 88         return ret;
 89     }
 90 
 91     bool set(int i, const T& e)
 92     {
 93         bool ret = ((0 <= i) && (i < m_length));
 94 
 95         if( ret )
 96         {
 97             Node* current = &m_header;
 98 
 99             for(int p=0; p<i; p++)
100             {
101                 current = current->next;
102             }
103 
104             current->next->value = e;
105         }
106 
107         return ret;
108     }
109 
110     bool get(int i, T& e) const
111     {
112         bool ret = ((0 <= i) && (i < m_length));
113 
114         if( ret )
115         {
116             Node* current = &m_header;
117 
118             for(int p=0; p<i; p++)
119             {
120                 current = current->next;
121             }
122 
123             e = current->next->value;
124         }
125 
126         return ret;
127     }
128 
129     int length() const
130     {
131         return m_length;
132     }
133 
134     void clear()
135     {
136         while( m_header.next )
137         {
138             Node* toDel = m_header.next;
139 
140             m_header.next = toDel->next;
141 
142             delete toDel;
143         }
144 
145         m_length = 0;
146     }
147 
148     ~LinkList()
149     {
150         clear();
151     }
152 };
153 
154 }
155 
156 #endif // LINKLIST_H

第110行的get是const函数,116行我们取m_header的指针,这时编译器会认为我们要改变m_header,编译会报错,因此,我们在第20行给m_header这个变量加上mutable属性。

测试程序如下:

 1 #include <iostream>
 2 #include "LinkList.h"
 3 
 4 
 5 using namespace std;
 6 using namespace DTLib;
 7 
 8 
 9 int main()
10 {
11 
12     LinkList<int> list;
13 
14     for(int i = 0; i<5; i++)
15     {
16         list.insert(i);
17     }
18 
19     for(int i = 0; i < list.length(); i++)
20     {
21         int v = 0;
22 
23         list.get(i, v);
24 
25         cout << v << endl;
26     }
27     return 0;
28 }

运行结果如下

技术分享图片

 

 

 get函数的使用不是很方便,我们添加一个重载函数:

  1 #ifndef LINKLIST_H
  2 #define LINKLIST_H
  3 
  4 #include "List.h"
  5 #include "Exception.h"
  6 
  7 namespace DTLib
  8 {
  9 
 10 template < typename T >
 11 class LinkList : public List<T>
 12 {
 13 protected:
 14     struct Node : public Object
 15     {
 16         T value;
 17         Node* next;
 18     };
 19 
 20     mutable Node m_header;
 21     int m_length;
 22 public:
 23     LinkList()
 24     {
 25         m_header.next = NULL;
 26         m_length = 0;
 27     }
 28 
 29     bool insert(const T& e)
 30     {
 31         return insert(m_length, e);
 32     }
 33 
 34     bool insert(int i, const T& e)
 35     {
 36         bool ret = ((0 <= i) && (i <= m_length));
 37 
 38         if( ret )
 39         {
 40             Node* node = new Node();
 41 
 42             if( node != NULL )
 43             {
 44                 Node* current = &m_header;
 45 
 46                 for(int p=0; p<i; p++)
 47                 {
 48                     current = current->next;
 49                 }
 50 
 51                 node->value = e;
 52                 node->next = current->next;
 53                 current->next = node;
 54 
 55                 m_length++;
 56             }
 57             else
 58             {
 59                 THROW_EXCEPTION(NoEnoughMemoryException, "No memery to insert new element...");
 60             }
 61         }
 62 
 63         return ret;
 64     }
 65 
 66     bool remove(int i)
 67     {
 68         bool ret = ((0 <= i) && (i < m_length));
 69 
 70         if( ret )
 71         {
 72             Node* current = &m_header;
 73 
 74             for(int p=0; p<i; p++)
 75             {
 76                 current = current->next;
 77             }
 78 
 79             Node* toDel = current->next;
 80 
 81             current->next = toDel->next;
 82 
 83             delete toDel;
 84 
 85             m_length--;
 86         }
 87 
 88         return ret;
 89     }
 90 
 91     bool set(int i, const T& e)
 92     {
 93         bool ret = ((0 <= i) && (i < m_length));
 94 
 95         if( ret )
 96         {
 97             Node* current = &m_header;
 98 
 99             for(int p=0; p<i; p++)
100             {
101                 current = current->next;
102             }
103 
104             current->next->value = e;
105         }
106 
107         return ret;
108     }
109 
110     T get(int i) const
111     {
112         T ret;
113 
114         if( get(i, ret) )
115         {
116             return ret;
117         }
118         else
119         {
120             THROW_EXCEPTION(IndexOutOfBoundsException, "Invalid parameter i to get element ...");
121         }
122 
123         return ret;
124     }
125 
126     bool get(int i, T& e) const
127     {
128         bool ret = ((0 <= i) && (i < m_length));
129 
130         if( ret )
131         {
132             Node* current = &m_header;
133 
134             for(int p=0; p<i; p++)
135             {
136                 current = current->next;
137             }
138 
139             e = current->next->value;
140         }
141 
142         return ret;
143     }
144 
145     int length() const
146     {
147         return m_length;
148     }
149 
150     void clear()
151     {
152         while( m_header.next )
153         {
154             Node* toDel = m_header.next;
155 
156             m_header.next = toDel->next;
157 
158             delete toDel;
159         }
160 
161         m_length = 0;
162     }
163 
164     ~LinkList()
165     {
166         clear();
167     }
168 };
169 
170 }
171 
172 #endif // LINKLIST_H

第110行为添加的重载的get函数,这个函数直接返回需要的值。

测试程序如下:

 1 #include <iostream>
 2 #include "LinkList.h"
 3 
 4 
 5 using namespace std;
 6 using namespace DTLib;
 7 
 8 
 9 int main()
10 {
11 
12     LinkList<int> list;
13 
14     for(int i = 0; i<5; i++)
15     {
16         list.insert(i);
17     }
18 
19     for(int i = 0; i < list.length(); i++)
20     {
21         cout << list.get(i) << endl;
22     }
23 
24     list.remove(2);
25 
26     for(int i = 0; i < list.length(); i++)
27     {
28         cout << list.get(i) << endl;
29     }
30 
31     return 0;
32 }

结果如下:

技术分享图片

 

问题:

头结点是否存在隐患?实现代码是否需要优化?

技术分享图片

 

我们定义的Node结构里面,只用到了next成员,而value成员是由用户指定的,如果用户自己定义了一个类型Test,在这个类型的构造函数中抛出异常。 如果用户使用这个Test类型来定义list的话,就会出现问题。

测试程序:

技术分享图片

结果如下:

技术分享图片

我们根本没有创建有问题的类Test的对象,只是创建了一个单链表LinkList的对象,而这确报错了。

没有创建Test类对象,就报错了,这时库的创建者是要负责的,而不是用户来负责。

 

以上是关于第二十二课 单链表的具体实现的主要内容,如果未能解决你的问题,请参考以下文章

第二册二十二课

Golang✔️走进 Go 语言✔️ 第二十二课 json & 文件读写

Golang✔️走进 Go 语言✔️ 第二十二课 json & 文件读写

第二十二课 打造专业的编译环境(下)

第二十二课 Shell的基础知识

快学Scala 第二十二课 (apply和unapply)