"《算法导论》之‘线性表’":基于指针实现的单链表
对于单链表的介绍部分参考自博文数组、单链表和双链表介绍 以及 双向链表的C/C++/Java实现。
1. 单链表介绍
单向链表(单链表)是链表的一种,它由节点组成,每个节点都包含下一个节点的指针。
1.1 单链表的示意图
表头为空,表头的后继节点是"节点10"(数据为10的节点),"节点10"的后继节点是"节点20"(数据为10的节点),...
1.2 单链表添加节点
在"节点10"与"节点20"之间添加"节点15"
添加之前:"节点10" 的后继节点为"节点20"。
添加之后:"节点10" 的后继节点为"节点15",而"节点15" 的后继节点为"节点20"。
需要注意的是在链表头部和其他地方添加结点是不一样的。
在链表头部添加结点的关键代码为:
- NodePointer ptr = new Node();
- ptr->data = val;
- ptr->next = head;
- head = ptr;
在其他地方添加结点的关键代码为:
- NodePointer ptr = new Node(), tmpPtr = head;
- ptr->data = val;
- while(...){...}
- ptr->next = tmpPtr->next;
- tmpPtr->next = ptr;
1.3 单链表删除节点
删除"节点30"
删除之前:"节点20" 的后继节点为"节点30",而"节点30" 的后继节点为"节点40"。
删除之后:"节点20" 的后继节点为"节点40"。
需要注意的是在链表首部、尾部和其他地方删除结点是不一样的。
在链表首部删除结点的关键代码为:
- NodePointer ptr = head, tmpPtr;
- ...if (pos == ) // 在链表第一个位置
- {
- head = ptr->next;
- delete ptr;
- }
在链表尾部删除结点的关键代码为:
- NodePointer ptr = head, tmpPtr;
- while (...){...}
- tmpPtr = ptr->next;
- ptr->next = NULL;
- delete tmpPtr;
在其他地方删除结点的关键代码为:
- NodePointer ptr = head, tmpPtr;
- while(...){...}
- tmpPtr = ptr->next;
- ptr->next = tmpPtr->next;
- delete tmpPtr;
2. 代码实现
对于单链表,我定义了一个这样的类LinkedList:
- // linkedlist.h
- #ifndef LINKEDLIST
- #define LINKEDLIST
- #include <iostream>
- #include <cassert>
- using namespace std;
- typedef int ElementType;
- class Node
- {
- public:
- ElementType data;
- Node * next;
- };
- typedef Node * NodePointer;
- class LinkedList
- {
- public:
- LinkedList();
- virtual ~LinkedList();
- LinkedList(const LinkedList& origlist); // 拷贝构造函数
- LinkedList& operator=(const LinkedList& origlist); // 赋值运算符重载
- void initList(ElementType * arr, int len);
- bool isEmpty();
- bool addNode(const int pos, const ElementType val);
- bool deleteNode(const int pos);
- void displayNodes();
- NodePointer getNode(const int pos);
- int getLenOfList();
- private:
- NodePointer head;
- };
- #endif // LINKEDLIST
实现代码如下:
- // linkedlist.cpp
- #include "linkedlist.h"
- LinkedList::LinkedList()
- {
- head = NULL;
- }
- LinkedList::~LinkedList()
- {
- NodePointer ptr = head, tmpPtr;
- while (ptr != NULL)
- {
- tmpPtr = ptr;
- ptr = ptr->next;
- delete tmpPtr;
- }
- }
- LinkedList::LinkedList(const LinkedList& origlist)
- {
- //head = origlist.head; // 很容易写成这样,这样会造成浅拷贝
- NodePointer ptr = origlist.head;
- int i = ;
- while (ptr != NULL)
- {
- addNode(i, ptr->data);
- ptr = ptr->next;
- i++;
- }
- }
- LinkedList& LinkedList::operator=(const LinkedList& origlist)
- {
- //head = origlist.head; // 很容易写成这样,这样会造成浅拷贝
- NodePointer ptr = origlist.head;
- int i = ;
- while (ptr != NULL)
- {
- addNode(i, ptr->data);
- ptr = ptr->next;
- i++;
- }
- return *this;
- }
- void LinkedList::initList(ElementType * arr, int len)
- {
- for (int i = ; i < len; i++)
- {
- addNode(i, arr[i]);
- }
- }
- bool LinkedList::isEmpty()
- {
- return head == NULL;
- }
- bool LinkedList::addNode(const int pos, const ElementType val)
- {
- bool success = true;
- int len = getLenOfList();
- // assert(0 <= pos <= len);
- if (pos < || pos > len)
- {
- cerr << "The node at position " << pos << " you want to add is less than zero or larger than "
- << "the length of list ." << endl;
- success = false;
- throw out_of_range("out_of_range");
- }
- else
- {
- NodePointer ptr = new Node();
- ptr->data = val;
- if (pos == ) // 如果添加的元素在第1个
- {
- ptr->next = head;
- head = ptr;
- }
- else // 其他
- {
- NodePointer tmpPtr = head;
- int count = ;
- while (tmpPtr != NULL && count < pos - )
- {
- tmpPtr = tmpPtr->next;
- count++;
- }
- ptr->next = tmpPtr->next;
- tmpPtr->next = ptr;
- }
- }
- return success;
- }
- bool LinkedList::deleteNode(const int pos)
- {
- bool success = true;
- int len = getLenOfList();
- if (len == )
- {
- cerr << "There is no element in the list." << endl;
- success = false;
- }
- else
- {
- NodePointer ptr = head, tmpPtr;
- int count = ;
- // assert(0 <= pos <= len);
- if (pos < || pos > len - )
- {
- cerr << "The node at position " << pos << " you want to delete is less than zero or larger than "
- << "the length of list ." << endl;
- success = false;
- throw out_of_range("out_of_range");
- }
- else if (pos == ) // 在链表第一个位置
- {
- head = ptr->next;
- delete ptr;
- }
- else if (pos == len - ) // 在链表最后一个位置
- {
- while (ptr != NULL && count < pos - )
- {
- ptr = ptr->next;
- count++;
- }
- tmpPtr = ptr->next;
- ptr->next = NULL;
- delete tmpPtr;
- }
- else // 其他
- {
- while (ptr != NULL && count < pos - )
- {
- ptr = ptr->next;
- count++;
- }
- tmpPtr = ptr->next;
- ptr->next = tmpPtr->next;
- delete tmpPtr;
- }
- }
- return success;
- }
- void LinkedList::displayNodes()
- {
- int len = getLenOfList();
- if (len == )
- {
- cerr << "There is no element in the list." << endl;
- }
- else
- {
- NodePointer ptr = head;
- int sequence = ;
- while (ptr != NULL)
- {
- cout << "Seq: " << sequence << "; Data: " << ptr->data << "."<< endl;;
- ptr = ptr->next;
- sequence++;
- }
- }
- }
- NodePointer LinkedList::getNode(const int pos)
- {
- int len = getLenOfList();
- if (len == )
- {
- cerr << "There is no element in the list." << endl;
- return NULL;
- }
- else
- {
- // assert(0 <= pos <= len);
- if (pos < || pos > len - )
- {
- cerr << "The item at position " << pos << " you want to get is less than zero or "
- << "larger than the length of list." << endl;
- throw out_of_range("out_of_range");
- // return NULL;
- }
- else
- {
- NodePointer ptr = head;
- int count = ;
- while (ptr != NULL && count < pos)
- {
- ptr = ptr->next;
- count++;
- }
- return ptr;
- }
- }
- }
- int LinkedList::getLenOfList()
- {
- int len = ;
- NodePointer ptr = head;
- while (ptr != NULL)
- {
- len++;
- ptr = ptr->next;
- }
- return len;
- }
linkedlist.cpp
Boost单元测试代码如下:
- // BoostUnitTest.cpp
- #define BOOST_TEST_MODULE LinkedList_Test_Module
- #include "stdafx.h"
- #include "D:\VSProject\Algorithm\List\LinkedList\SingleLinkedList_BasedOnPointer\SingleLinkedList\SingleLinkedList\linkedlist.h"
- struct LinkedList_Fixture
- {
- public:
- LinkedList_Fixture()
- {
- testLinkedList = new LinkedList();
- }
- ~LinkedList_Fixture()
- {
- delete testLinkedList;
- }
- LinkedList * testLinkedList;
- };
- BOOST_FIXTURE_TEST_SUITE(LinkedList_Test_Suite, LinkedList_Fixture)
- BOOST_AUTO_TEST_CASE( LinkedList_Normal_Test )
- {
- // isEmpty --------------------------------------------
- BOOST_REQUIRE(testLinkedList->isEmpty() == true);
- // getLenOfList ---------------------------------------
- BOOST_REQUIRE(testLinkedList->getLenOfList() == );
- // addNode & getNode ---------------------------------
- BOOST_REQUIRE(testLinkedList->addNode(, ) == true);
- BOOST_REQUIRE((testLinkedList->getNode())->data == );
- BOOST_REQUIRE((testLinkedList->getNode())->next == NULL);
- BOOST_REQUIRE(testLinkedList->isEmpty() == false);
- BOOST_REQUIRE(testLinkedList->getLenOfList() == );
- BOOST_REQUIRE(testLinkedList->addNode(, ) == true);
- BOOST_REQUIRE((testLinkedList->getNode())->data == );
- BOOST_REQUIRE((testLinkedList->getNode())->next == NULL);
- BOOST_REQUIRE(testLinkedList->isEmpty() == false);
- BOOST_REQUIRE(testLinkedList->getLenOfList() == );
- BOOST_REQUIRE(testLinkedList->addNode(, ) == true);
- BOOST_REQUIRE((testLinkedList->getNode())->data == );
- BOOST_REQUIRE((testLinkedList->getNode())->next != NULL);
- BOOST_REQUIRE(testLinkedList->isEmpty() == false);
- BOOST_REQUIRE(testLinkedList->getLenOfList() == );
- // deleteNode -----------------------------------------
- BOOST_REQUIRE(testLinkedList->deleteNode() == true);
- BOOST_REQUIRE((testLinkedList->getNode())->data == );
- BOOST_REQUIRE(testLinkedList->getLenOfList() == );
- BOOST_REQUIRE(testLinkedList->deleteNode() == true);
- BOOST_REQUIRE((testLinkedList->getNode())->data == );
- BOOST_REQUIRE(testLinkedList->getLenOfList() == );
- BOOST_REQUIRE(testLinkedList->deleteNode() == true);
- BOOST_REQUIRE(testLinkedList->getLenOfList() == );
- // initList -------------------------------------------
- int arr[] = { , , };
- int len = sizeof(arr) / sizeof(int);
- testLinkedList->initList(arr, len);
- BOOST_REQUIRE(testLinkedList->getLenOfList() == );
- BOOST_REQUIRE((testLinkedList->getNode())->data == );
- BOOST_REQUIRE((testLinkedList->getNode())->data == );
- BOOST_REQUIRE((testLinkedList->getNode())->data == );
- BOOST_REQUIRE((testLinkedList->getNode())->next == NULL);
- }
- BOOST_AUTO_TEST_CASE(LinkedList_Abnormal_Test)
- {
- int arr[] = { , , };
- int len = sizeof(arr) / sizeof(int);
- testLinkedList->initList(arr, len);
- // addNode -------------------------------------------
- BOOST_REQUIRE_THROW(testLinkedList->addNode(-, ), out_of_range);
- BOOST_REQUIRE_THROW(testLinkedList->addNode(, ), out_of_range);
- // deleteNode ----------------------------------------
- BOOST_REQUIRE_THROW(testLinkedList->deleteNode(-), out_of_range);
- BOOST_REQUIRE_THROW(testLinkedList->deleteNode(), out_of_range);
- // getNode --------------------------------------------
- BOOST_REQUIRE_THROW(testLinkedList->getNode(-), out_of_range);
- BOOST_REQUIRE_THROW(testLinkedList->getNode(), out_of_range);
- }
- BOOST_AUTO_TEST_CASE(LinkedList_CopyConstuctor_Test)
- {
- int arr[] = { , , };
- int len = sizeof(arr) / sizeof(int);
- testLinkedList->initList(arr, len);
- //LinkedList * testLinkedList2(testLinkedList); // 特别容易写成这样,这样导致的结果就是testLinkedList2和
- // testLinkedList指向同一块内存这样的写法才是正确的
- // 该句等同于
- // LinkedList * testLinkedList2;
- // testLinkedList2 = testLinkedList;
- //LinkedList testLinkedList2(*testLinkedList); // 要不就这样子定义,只不过此时testLinkedList2不是一个指针
- LinkedList * testLinkedList3 = new LinkedList(*testLinkedList);
- BOOST_REQUIRE(testLinkedList3->getLenOfList() == );
- BOOST_REQUIRE((testLinkedList3->getNode())->data == );
- BOOST_REQUIRE((testLinkedList3->getNode())->data == );
- BOOST_REQUIRE((testLinkedList3->getNode())->data == );
- BOOST_REQUIRE((testLinkedList3->getNode())->next == NULL);
- }
- BOOST_AUTO_TEST_CASE(LinkedList_EqualOperator_Test)
- {
- int arr[] = { , , };
- int len = sizeof(arr) / sizeof(int);
- testLinkedList->initList(arr, len);
- // LinkedList * testLinkedList2 = testLinkedList; // 错误的写法
- LinkedList * testLinkedList2 = new LinkedList();
- *testLinkedList2 = *testLinkedList;
- BOOST_REQUIRE(testLinkedList2->getLenOfList() == );
- BOOST_REQUIRE((testLinkedList2->getNode())->data == );
- BOOST_REQUIRE((testLinkedList2->getNode())->data == );
- BOOST_REQUIRE((testLinkedList2->getNode())->data == );
- BOOST_REQUIRE((testLinkedList2->getNode())->next == NULL);
- }
- BOOST_AUTO_TEST_SUITE_END()
BoostUnitTest.cpp
本篇博文的代码均托管到Taocode : http://code.taobao.org/p/datastructureandalgorithm/src/.
"《算法导论》之‘线性表’":基于指针实现的单链表的更多相关文章
- "《算法导论》之‘线性表’":基于数组实现的单链表
对于单链表,我们大多时候会用指针来实现(可参考基于指针实现的单链表).现在我们就来看看怎么用数组来实现单链表. 1. 定义单链表中结点的数据结构 typedef int ElementType; cl ...
- JavaScript 数据结构与算法之美 - 线性表(数组、栈、队列、链表)
前言 基础知识就像是一座大楼的地基,它决定了我们的技术高度. 我们应该多掌握一些可移值的技术或者再过十几年应该都不会过时的技术,数据结构与算法就是其中之一. 栈.队列.链表.堆 是数据结构与算法中的基 ...
- ACM金牌选手算法讲解《线性表》
哈喽,大家好,我是编程熊,双非逆袭选手,字节跳动.旷视科技前员工,ACM亚洲区域赛金牌,保研985研究生,分享算法与数据结构.计算机学习经验,帮助大家进大厂~ 公众号:『编程熊』 文章首发于: ACM ...
- 已知长度为n的线性表采用顺序结构,写一算法删除该线性表中所有值为item的元素
/** * @author:(LiberHome) * @date:Created in 2019/2/27 23:34 * @description: * @version:$ */ /*已知长度为 ...
- 数据结构与算法系列2 线性表 使用java实现动态数组+ArrayList源码详解
数据结构与算法系列2 线性表 使用java实现动态数组+ArrayList源码详解 对数组有不了解的可以先看看我的另一篇文章,那篇文章对数组有很多详细的解析,而本篇文章则着重讲动态数组,另一篇文章链接 ...
- 数据结构(1) 第一天 算法时间复杂度、线性表介绍、动态数组搭建(仿Vector)、单向链表搭建、企业链表思路
01 数据结构基本概念_大O表示法 无论n是多少都执行三个具体步骤 执行了12步 O(12)=>O(1) O(n) log 2 N = log c N / log c N (相当于两个对数进行了 ...
- 数据结构与算法系列2 线性表 链表的分类+使用java实现链表+链表源码详解
数据结构与算法系列2.2 线性表 什么是链表? 链表是一种物理存储单元上非连续,非顺序的存储结构,数据元素的逻辑顺序是通过链表的链接次序实现的一系列节点组成,节点可以在运行时动态生成,每个节点包括两个 ...
- javascript实现数据结构与算法系列:线性表的静态单链表存储结构
有时可借用一维数组来描述线性链表,这就是线性表的静态单链表存储结构. 在静态链表中,数组的一个分量表示一个结点,同时用游标(cur)代替指针指示结点在数组中的相对位置.数组的第0分量可看成头结点,其指 ...
- 数据结构导论 四 线性表的顺序存储VS链式存储
前几章已经介绍到了顺序存储.链式存储 顺序存储:初始化.插入.删除.定位 链式存储:初始化.插入.删除.定位 顺序存储:初始化 strudt student{ int ID://ID char nam ...
随机推荐
- Java异常处理-----运行时异常(RuntimeException)
RuntimeException RunntimeException的子类: ClassCastException 多态中,可以使用Instanceof 判断,进行规避 ArithmeticExcep ...
- 1.cocos2dx 3.2环境搭建
1 所需软件 jdk-7u25-windows-i586.exe python-2.7.8.amd64.msi cocos2d-x-3.2.zip apache-ant-1.9.4.zi ...
- JAVA面向对象-----值交换(基本数据类型 数组类型 对象的值 字符串的)
JAVA面向对象-–值交换 基本数据类型交换 数组类型交换 对象的值交换 字符串的值交换 恩,没错,又是贴图,请大家见谅,我也是为了多写几个文章,请大家谅解. 字符串的值交换: 交换值失败. 这个文章 ...
- Linux proc/pid/task/tid/stat文件详解
[root@localhost ~]# cat /proc/6873/stat6873 (a.out) R 6723 6873 6723 34819 6873 8388608 77 0 0 0 419 ...
- 04_关于元数据,ResultSetMetaData对象以及API方法介绍
ResultSetMetaData对象 元数据,可以理解为数据的数据 Jdbc中的元数据是指数据库.表.列的定义信息. ResultSetMetaData对象表示结果集ResultSet对象的元 ...
- Python图片处理库之PIL
这个模块对于Python2.7 的windows64位电脑而言,还真的是不好找啊.这里分享一个下载链接吧,需要的朋友可以下载下来.PIL For Windows64 Python2.7下面分享一下这个 ...
- Runtime系列(二)--Runtime的使用场景
Runtime 理解介绍的文章非常多,我只想讲讲Runtime 可以用在哪里,而我在项目里哪些地方用到了runtime.多以实际使用过程为主,来介绍runtime的使用. * 那么runtime 怎么 ...
- 安卓java.lang.IllegalStateException: The specified child already has a parent.解决方案
在使用ViewPager的时候遇到一个错误java.lang.IllegalStateException: The specified child already has a parent. You ...
- 【Unity技巧】LOGO闪光效果
写在前面 本文参考了风宇冲的博文,在按照这篇博文实现LOGO闪光时,发现了一些问题.最严重的就是背景无法透明,看上去背景始终是黑色的:其次就是各个变量的意义不是非常明确,调节起来不方便:而且在闪光条的 ...
- Java进阶(三十一) Web服务调用
Java进阶(三十一) Web服务调用 前言 有朋友问了一个问题:如何调用已知的音乐服务接口,服务文档如下: https://www.evernote.com/shard/s744/sh/c37cd5 ...