对于单链表的介绍部分参考自博文数组、单链表和双链表介绍 以及 双向链表的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. "《算法导论》之‘线性表’":基于数组实现的单链表

    对于单链表,我们大多时候会用指针来实现(可参考基于指针实现的单链表).现在我们就来看看怎么用数组来实现单链表. 1. 定义单链表中结点的数据结构 typedef int ElementType; cl ...

  2. JavaScript 数据结构与算法之美 - 线性表(数组、栈、队列、链表)

    前言 基础知识就像是一座大楼的地基,它决定了我们的技术高度. 我们应该多掌握一些可移值的技术或者再过十几年应该都不会过时的技术,数据结构与算法就是其中之一. 栈.队列.链表.堆 是数据结构与算法中的基 ...

  3. ACM金牌选手算法讲解《线性表》

    哈喽,大家好,我是编程熊,双非逆袭选手,字节跳动.旷视科技前员工,ACM亚洲区域赛金牌,保研985研究生,分享算法与数据结构.计算机学习经验,帮助大家进大厂~ 公众号:『编程熊』 文章首发于: ACM ...

  4. 已知长度为n的线性表采用顺序结构,写一算法删除该线性表中所有值为item的元素

    /** * @author:(LiberHome) * @date:Created in 2019/2/27 23:34 * @description: * @version:$ */ /*已知长度为 ...

  5. 数据结构与算法系列2 线性表 使用java实现动态数组+ArrayList源码详解

    数据结构与算法系列2 线性表 使用java实现动态数组+ArrayList源码详解 对数组有不了解的可以先看看我的另一篇文章,那篇文章对数组有很多详细的解析,而本篇文章则着重讲动态数组,另一篇文章链接 ...

  6. 数据结构(1) 第一天 算法时间复杂度、线性表介绍、动态数组搭建(仿Vector)、单向链表搭建、企业链表思路

    01 数据结构基本概念_大O表示法 无论n是多少都执行三个具体步骤 执行了12步 O(12)=>O(1) O(n) log 2 N = log c N / log c N (相当于两个对数进行了 ...

  7. 数据结构与算法系列2 线性表 链表的分类+使用java实现链表+链表源码详解

    数据结构与算法系列2.2 线性表 什么是链表? 链表是一种物理存储单元上非连续,非顺序的存储结构,数据元素的逻辑顺序是通过链表的链接次序实现的一系列节点组成,节点可以在运行时动态生成,每个节点包括两个 ...

  8. javascript实现数据结构与算法系列:线性表的静态单链表存储结构

    有时可借用一维数组来描述线性链表,这就是线性表的静态单链表存储结构. 在静态链表中,数组的一个分量表示一个结点,同时用游标(cur)代替指针指示结点在数组中的相对位置.数组的第0分量可看成头结点,其指 ...

  9. 数据结构导论 四 线性表的顺序存储VS链式存储

    前几章已经介绍到了顺序存储.链式存储 顺序存储:初始化.插入.删除.定位 链式存储:初始化.插入.删除.定位 顺序存储:初始化 strudt student{ int ID://ID char nam ...

随机推荐

  1. MyEclipse如何全局搜索

    1全局搜索的启动方式 CTRL+H 2全局搜索自己选择搜索方式 自己选择要搜索的东西,简单吧,里面还有很多好玩的东西需要你去发现,加油! [正在看本人博客的这位童鞋,我看你气度不凡,谈吐间隐隐有王者之 ...

  2. 给pdf文件添加防伪水印logo(附工程源码下载)

    pdf添加水印logo这种需求场景确实很少,有些时候一些销售单据生成pdf添加一个水印logo,做一个简单的防伪效果,虽然实际上并没有太大作用,但是产品经理说要,巴拉巴拉--省略一万字. 下面将源码分 ...

  3. intent flags标记

    Intent Flag介绍 FLAG_ACTIVITY_BROUGHT_TO_FRONT  这个标志一般不是由程序代码设置的,如在launchMode中设置singleTask模式时系统帮你设定. F ...

  4. [linux RedHat]windows下使用putty远程连接linux 下载JDK和tomcat

    本文地址:http://blog.csdn.net/sushengmiyan/article/details/43154543 本文作者:sushengmiyan ------------------ ...

  5. 18 UI美化自定义主题样式代码

    自定义主题 假设我们我们对现有的样式不大满意 那么可在工程目录res/values下的styles.xml自定义 方法: 1. res/values下的styles.xml文件中自定义一个标签 < ...

  6. API创建员工Element

    DECLARE ln_element_link_id PAY_ELEMENT_LINKS_F.ELEMENT_LINK_ID%TYPE; ld_effective_start_date DATE; l ...

  7. 深入浅出Tabhost+简单入门Demo

    小伙伴们在手机上逛淘宝的时候,会发现在淘宝的下面有个按钮,分别是首页.微淘.社区.购物车和我的淘宝,点击不同的按钮会跳转到不同的页面,目前小编所接手的这个项目,也需要用到类似这样的功能,小编就发挥网络 ...

  8. 如何在SpriteBuilder中设置对象的通用属性

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 我们知道在SpriteBuilder中可以为对象设置自定义类从 ...

  9. Android实现系统ROOT, 并能赋予app root权限

    1. 获取root权限 -->  修改adb源码     a. 打开 system/core/adb/adb_main.cpp,或者是 system/core/adb/daemon/main.c ...

  10. iOS下WebRTC音视频通话(一)

    在iOS下做IM功能时,难免都会涉及到音频通话和视频通话.QQ中的QQ电话和视频通话效果就非常好,但是如果你没有非常深厚的技术,也没有那么大的团队,很难做到QQ那么快速和稳定的通话效果. 但是利用We ...