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

本节目标:

添加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类对象,就报错了,这时库的创建者是要负责的,而不是用户来负责。

原文地址:https://www.cnblogs.com/wanmeishenghuo/p/9650109.html

时间: 2024-10-24 19:45:53

第二十二课 单链表的具体实现的相关文章

第二十四课 单链表的遍历与优化

问题: 如何遍历单链表中的每一个元素? 示例: 在头部插入元素时,时间复杂度是O(n). 获取元素时,时间复杂度是O(n*n),因为内层定位位置时有一个O(n)复杂度. 从理论上来说遍历一个单链表,只需要线性的时间就够了. 设计思路: 提供一组相关的遍历函数,遍历时使用这些函数来操作: move函数的i参数为目标位置,step参数为每次移动的节点数. end用来判断当前的游标是否到达了单链表的尾部. current返回当前游标指向的数据元素. next移动游标,移动的次数根据move中的step

NeHe OpenGL教程 第二十二课:凹凸映射

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第二十二课:凹凸映射 凹凸映射,多重纹理扩展: 这是一课高级教程,请确信你对基本知识已经非常了解了.这一课是基于第六课的代码的,它将建立一个非常酷的立体纹理效果. 这一课由Jens Schneider所写,它基本上是由第6课改写而来

嵌入式 Linux C语言(十二)——单链表

嵌入式 Linux C语言(十二)--单链表 一.单链表简介 1.单链表的结构 单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素. 链表中的数据是以节点来表示的,每个节点由两部分构成:一个是数据域,存储数据值,另一个是指针域,存储指向下一个节点的指针. 2.单链表的节点 单链表节点的数据结构如下: typedef struct data { unsigned int id;//学生身份ID char name[LENGTH];//学生姓名 char subject[

《剑指offer》第二十二题(链表中倒数第k个结点)

// 面试题22:链表中倒数第k个结点 // 题目:输入一个链表,输出该链表中倒数第k个结点.为了符合大多数人的习惯, // 本题从1开始计数,即链表的尾结点是倒数第1个结点.例如一个链表有6个结点, // 从头结点开始它们的值依次是1.2.3.4.5.6.这个链表的倒数第3个结点是 // 值为4的结点. //O(n)的解法:维护两个指针,让A走B前头,前K步,A到头,B就是解了,但是这个问题在于程序鲁棒性 #include <iostream> #include "List.h&q

《剑指offer》第二十二题:链表中倒数第k个结点

// 面试题22:链表中倒数第k个结点 // 题目:输入一个链表,输出该链表中倒数第k个结点.为了符合大多数人的习惯, // 本题从1开始计数,即链表的尾结点是倒数第1个结点.例如一个链表有6个结点, // 从头结点开始它们的值依次是1.2.3.4.5.6.这个链表的倒数第3个结点是 // 值为4的结点. #include <cstdio> #include "List.h" ListNode* FindKthToTail(ListNode* pListHead, unsi

JAVA学习第二十二课(多线程(二))- (多线程的创建方式一 :继承Thread类)

线程是程序中的执行线程.Java 虚拟机允许应用程序并发地运行多个执行线程. 创建新执行线程有两种方法. 一种方法是将类声明为 Thread 的子类.该子类应重写Thread 类的run 方法.另一种方法是声明实现 Runnable 接口的类.该类然后实现run 方法. 创建线程方式一:继承Thread类 一.创建线程的步骤: 1.定义一个类继承Thread类 2.覆盖Thread中的run()方法 3.直接创建Thread类子类的对象 4.调用start方法开启线程,并调用线程的任务run方法

linux学习笔记-第二十二课-LNMP环境搭建(一)

一.LNMP环境搭建前的准备 LNMP就是Linux系统下Nginx+MySQL+PHP这种网站服务器架构,所以需要下载mysql,php,与nginx这三套软件. MySQL : 32位 :http://syslab.comsenz.com/downloads/linux/mysql-5.1.40-linux-i686-icc-glibc23.tar.gz 64位 :http://syslab.comsenz.com/downloads/linux/mysql-5.1.40-linux-x86

第二十二课 Shell的基础知识

一.shell介绍1.shell是一个命令解释器,提供用户和机器进行交互,每个用户都可以有自己特定的shell ,2.CentOS7 默认shell为bash,还有zsh,ksh它们有细节上的差异而已,我们可以查下系统中是否存在zsh: yum list |grep zsh bash有哪些特性? 二.命令历史(history)1.它的存储的文件为:/root/.bash_history 2.当我们退出终端后,它才会储存到以上的文件中.它的配制文件为:/etc/profile ,如果你修改里面的文

20.2015.8.12第二十二课ado.net1,2(增删改查代码)

//demo.aspx.cs登陆页面代码using System; using System.Collections.Generic; using System.Configuration; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using System.Data.SqlClient; namespace web20150811 { public par