对于单链表,我们大多时候会用指针来实现(可参考基于指针实现的单链表)。现在我们就来看看怎么用数组来实现单链表。

  1. 定义单链表中结点的数据结构

 typedef int ElementType;
class NodeType
{
public:
ElementType data;
int next;
};

  该结点包括了两个元素,其一是数据,另一个是指向下一个结点的“指针”(在这篇文章中实际上是指用于实现单链表的数组的下标。)

   2. 定义一个的数组

 const int CAPACITY = ;
NodeType node[CAPACITY];

  在内存中该数组的结构如下图:

  

   3. 定义指向单链表第1个结点的“指针”

 int head;

   4. 一个简单的单链表例子

  我们假设单链表只有3个结点,并且3个结点从左到右分别位于数组node中第0、1、2位置,如下图:

  

  head指向链表中的第1个结点。该结点存储于数组node的第0位置,data为111,next指向下一结点。其他以此类推。

  需要注意的是链表的中最后一个结点(即上图中的第3个结点)的next被置为-1,表示不指向任何结点。

  更为重要的是,这三个结点是可以位于数组node中的任一位置的,只要他们之间保持这种链接的关系。

   5. 实际程序实现

  在实际程序实现中,为了便于判断数组中哪一个元素已经被使用,我在原单链表的结点数据结构中又添加了一个判断位,如下:

 typedef int ElementType;
class NodeType
{
public:
NodeType() { data = ; next = NULL_VALUE; isFree = true; };
~NodeType() {};
ElementType data;
int next;
bool isFree; // 标志位,为true表示该结点可用,反之不可用
};

  其余的程序摘录如下:

 #ifndef SINGLELINKEDLIST
#define SINGLELINKEDLIST #include <iostream>
#include <cassert>
using namespace std; const int CAPACITY = ;
const int NULL_VALUE = -; typedef int ElementType;
class NodeType
{
public:
NodeType() { data = ; next = NULL_VALUE; isFree = true; };
~NodeType() {};
ElementType data;
int next;
bool isFree; // 标志位,为true表示该结点可用,反之不可用
}; class LinkedList
{
public:
LinkedList();
virtual ~LinkedList();
void initList(ElementType * arr, int len);
bool isEmpty();
int findFreeNode();
bool addNode(const int pos, const ElementType val);
bool deleteNode(const int pos);
void displayNodes();
NodeType getNode(const int pos);
int getLenOfList(); private:
NodeType node[CAPACITY];
int head; }; #endif;

linkedlist.h

 #include "linkedlist.h"

 LinkedList::LinkedList()
{
head = NULL_VALUE;
} LinkedList::~LinkedList()
{
for (int i = ; i < CAPACITY; i++)
{
node[i].data = ;
node[i].next = NULL_VALUE;
node[i].isFree = true;
}
} void LinkedList::initList(ElementType * arr, int len)
{
for (int i = ; i < len; i++)
{
int tmp = arr[i];
addNode(i, tmp);
}
} bool LinkedList::isEmpty()
{
return head == NULL_VALUE;
} int LinkedList::findFreeNode()
{
int i = ;
while (node[i].isFree == false)
{
i++;
if (i == CAPACITY) // 如果找不到可用的结点,返回NULL_VALUE
{
return NULL_VALUE;
}
}
return i;
} bool LinkedList::addNode(const int pos, const ElementType val)
{
bool success = true;
int len = getLenOfList();
if (len == CAPACITY)
{
cerr << "There is no space in the list." << endl;
success = false;
}
else
{
// assert(0 <= pos <= CAPACITY);
if (pos < || pos > len)
{
cerr << "The node at position " << pos << " you want to add is less than zero or larger than "
<< "the capacity of list ." << endl;
success = false;
throw out_of_range("out_of_range");
}
else
{
int freeNode = findFreeNode();
node[freeNode].data = val;
node[freeNode].isFree = false;
if (pos == ) // 如果添加的元素在第1个
{
node[freeNode].next = head;
head = freeNode;
}
else // 其他
{
int ptr = head;
int count = ;
while (ptr != NULL_VALUE && count < pos - )
{
ptr = node[ptr].next;
count++;
}
node[freeNode].next = node[ptr].next;
node[ptr].next = freeNode;
}
}
}
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
{
int 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 = node[head].next;
node[ptr].data = ;
node[ptr].next = NULL_VALUE;
node[ptr].isFree = true;
}
else if (pos == len - ) // 在链表最后一个位置
{
while (ptr != NULL && count < pos - )
{
ptr = node[ptr].next;
count++;
}
tmpPtr = node[ptr].next;
node[ptr].next = NULL_VALUE;
// reset the deleted one
node[tmpPtr].data = ;
node[tmpPtr].next = NULL_VALUE;
node[tmpPtr].isFree = true;
}
else // 其他
{
while (ptr != NULL && count < pos - )
{
ptr = node[ptr].next;
count++;
}
tmpPtr = node[ptr].next;
node[ptr].next = node[tmpPtr].next;
// reset the deleted one
node[tmpPtr].data = ;
node[tmpPtr].next = NULL_VALUE;
node[tmpPtr].isFree = true;
}
}
return success;
} void LinkedList::displayNodes()
{
int ptr = head;
int sequence = ;
while (ptr != NULL_VALUE)
{
cout << "Seq: " << sequence << "; Data: " << node[ptr].data << endl;
ptr = node[ptr].next;
sequence++;
}
} NodeType LinkedList::getNode(const int pos)
{
NodeType tmpNode;
int len = getLenOfList();
if (len == )
{
cerr << "There is no element in the list." << endl;
}
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 tmpNode;
}
else
{
int ptr = head;
int count = ;
while (ptr != NULL_VALUE && count < pos)
{
ptr = node[ptr].next;
count++;
}
tmpNode.data = node[ptr].data;
tmpNode.next = node[ptr].next;
tmpNode.isFree = node[ptr].isFree;
}
} return tmpNode;
} int LinkedList::getLenOfList()
{
int ptr = head;
int len = ;
while (ptr != NULL_VALUE)
{
ptr = node[ptr].next;
len++;
} return len;
}

linkedlist.cpp

  Boost单元测试代码测试如下:

 #define BOOST_TEST_MODULE LinkedList_Test_Module

 #include "stdafx.h"
#include "D:\VSProject\Algorithm\List\LinkedList\SingleLinkedList_BasedOnArray\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() == ); // findFreeNode --------------------------------------
BOOST_REQUIRE(testLinkedList->findFreeNode() == ); // addNode & getNode ---------------------------------
BOOST_REQUIRE(testLinkedList->addNode(, ) == true);
BOOST_REQUIRE((testLinkedList->getNode()).data == );
BOOST_REQUIRE((testLinkedList->getNode()).next == NULL_VALUE);
BOOST_REQUIRE((testLinkedList->getNode()).isFree == false);
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_VALUE);
BOOST_REQUIRE((testLinkedList->getNode()).isFree == false);
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_VALUE);
BOOST_REQUIRE((testLinkedList->getNode()).isFree == false);
BOOST_REQUIRE((testLinkedList->getNode()).next == NULL_VALUE);
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()).next == ); BOOST_REQUIRE((testLinkedList->getNode()).data == );
BOOST_REQUIRE((testLinkedList->getNode()).next == ); BOOST_REQUIRE((testLinkedList->getNode()).data == );
BOOST_REQUIRE((testLinkedList->getNode()).next == NULL_VALUE);
} 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_SUITE_END()

BoostUnitTest.cpp

  本篇博文的代码均托管到Taocode : http://code.taobao.org/p/datastructureandalgorithm/src/.

"《算法导论》之‘线性表’":基于数组实现的单链表的更多相关文章

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

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

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

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

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

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

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

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

  5. "《算法导论》之‘线性表’":基于指针实现的单链表

    对于单链表的介绍部分参考自博文数组.单链表和双链表介绍 以及 双向链表的C/C++/Java实现. 1. 单链表介绍 单向链表(单链表)是链表的一种,它由节点组成,每个节点都包含下一个节点的指针.   ...

  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. 【数据结构&算法】05-线性表之数组

    目录 前言 线性结构与非线性结构 数组 数组的两个限制 数组的随机访问特性 数组的操作 插入操作 删除操作 数组越界 容器 数组下标 前言 本笔记主要记录数组的一些基础特性及操作. 顺便解答下为什么大 ...

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

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

随机推荐

  1. foxit pdf强制页面视图所有情况都为'合适宽度'

    在左边的书签点击时,有时明明已经设置为合适宽度,但foxit会自动给你变为'合适页面'.真是莫名其妙的设置.好在可以这样更改:

  2. Memcached - Base

    Memcached 标签 : Java与NoSQL 在程序的实现中, 经常会忽略程序的运行时间. 即使采用类似的实现方法, 有时候运行速度也会相差很多. 大多数情况下, 这一速度上的差异是由数据访问速 ...

  3. 手把手图文并茂教你发布Android开源库

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼,文章链接: http://blog.csdn.net/hejjunlin/article/details/52452220 经常逛githu ...

  4. Shell脚本生成网页版相册浏览器

    今天学到了一招,那就是使用脚本制作一款网页版相册浏览器.先上图吧. 必备基础 操作系统: 以linux为内核的操作系统都行 编程语言:Shell(bash)脚本,相关基础知识即可 下载工具:wget ...

  5. java之IO流详解(二)

    好了,昨天讲了字节流,现在我们就来讲字符流吧... 字符流可以这样理解,字符流 = 字节流 + 编码表,目的是为了更好的操作中文字符(注:字符流只可以可以操作字符类型的文件,不能操作影音图像文件,要操 ...

  6. K均值聚类的失效性分析

    K均值聚类是一种应用广泛的聚类技术,特别是它不依赖于任何对数据所做的假设,比如说,给定一个数据集合及对应的类数目,就可以运用K均值方法,通过最小化均方误差,来进行聚类分析. 因此,K均值实际上是一个最 ...

  7. 非ROOT实现静默安装的一些思考与体会,AIDL获取IPackageManager,反射ServiceManager,系统签名

    非ROOT实现静默安装的一些思考与体会,AIDL获取IPackageManager,反射ServiceManager,系统签名 最近自家的系统要做一个升级服务,里面有三个功能,第一个是系统升级,也就是 ...

  8. [ExtJS5学习笔记]第五节 使用fontawesome给你的extjs5应用增加字体图标

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

  9. Dynamics CRM 插件Plugin中获取和更新时间字段值的准确转换

    前面两篇介绍了后台代码通过组织服务获取更新时间字段.窗体javascript通过Odata获取更新时间字段,最后篇来实验下在插件中的获取和更新时间字段是否需要时制的转化,为何说是最后篇呢,因为在CRM ...

  10. Android四大组件之一Service介绍-android学习之旅(十二)

    基本概念: service是android四大组件之一,运行在后台执行耗时操作,并不提供用户界面.其他组件如acticity可以通过startService启动该组件,也可以通过bindService ...