"《算法导论》之‘线性表’":基于数组实现的单链表
对于单链表,我们大多时候会用指针来实现(可参考基于指针实现的单链表)。现在我们就来看看怎么用数组来实现单链表。
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/.
"《算法导论》之‘线性表’":基于数组实现的单链表的更多相关文章
- JavaScript 数据结构与算法之美 - 线性表(数组、栈、队列、链表)
前言 基础知识就像是一座大楼的地基,它决定了我们的技术高度. 我们应该多掌握一些可移值的技术或者再过十几年应该都不会过时的技术,数据结构与算法就是其中之一. 栈.队列.链表.堆 是数据结构与算法中的基 ...
- 数据结构与算法系列2 线性表 使用java实现动态数组+ArrayList源码详解
数据结构与算法系列2 线性表 使用java实现动态数组+ArrayList源码详解 对数组有不了解的可以先看看我的另一篇文章,那篇文章对数组有很多详细的解析,而本篇文章则着重讲动态数组,另一篇文章链接 ...
- ACM金牌选手算法讲解《线性表》
哈喽,大家好,我是编程熊,双非逆袭选手,字节跳动.旷视科技前员工,ACM亚洲区域赛金牌,保研985研究生,分享算法与数据结构.计算机学习经验,帮助大家进大厂~ 公众号:『编程熊』 文章首发于: ACM ...
- 已知长度为n的线性表采用顺序结构,写一算法删除该线性表中所有值为item的元素
/** * @author:(LiberHome) * @date:Created in 2019/2/27 23:34 * @description: * @version:$ */ /*已知长度为 ...
- "《算法导论》之‘线性表’":基于指针实现的单链表
对于单链表的介绍部分参考自博文数组.单链表和双链表介绍 以及 双向链表的C/C++/Java实现. 1. 单链表介绍 单向链表(单链表)是链表的一种,它由节点组成,每个节点都包含下一个节点的指针. ...
- 数据结构(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 线性表 什么是链表? 链表是一种物理存储单元上非连续,非顺序的存储结构,数据元素的逻辑顺序是通过链表的链接次序实现的一系列节点组成,节点可以在运行时动态生成,每个节点包括两个 ...
- 【数据结构&算法】05-线性表之数组
目录 前言 线性结构与非线性结构 数组 数组的两个限制 数组的随机访问特性 数组的操作 插入操作 删除操作 数组越界 容器 数组下标 前言 本笔记主要记录数组的一些基础特性及操作. 顺便解答下为什么大 ...
- javascript实现数据结构与算法系列:线性表的静态单链表存储结构
有时可借用一维数组来描述线性链表,这就是线性表的静态单链表存储结构. 在静态链表中,数组的一个分量表示一个结点,同时用游标(cur)代替指针指示结点在数组中的相对位置.数组的第0分量可看成头结点,其指 ...
随机推荐
- Scheme call/cc 研究
目前尚不清楚实质,但已经能够从形式上理解它的某些好处,有个很简单的连乘函数可以说明: 为了展示究竟发生了什么,我包装了下乘法函数,将其变为mul. 我们将比较product和xproduct的区别. ...
- [error]configure: error: You need a C++ compiler for C++ support.
安装pcre包的时候提示缺少c++编译器 解决办法 使用yum安装 yum -y install gcc-c++ 本文出自 "orangleliu笔记本"博客,转载请务必保留此出处 ...
- Java并发框架——AQS之原子性如何保证?
在研究AQS框架时,会发现这个类很多地方都使用了CAS操作,在并发实现中CAS操作必须具备原子性,而且是硬件级别的原子性,java被隔离在硬件之上,明显力不从心,这时为了能直接操作操作系统层面,肯定要 ...
- 高通msm8994手动提升性能脚本
点击打开链接 [plain] view plain copy stop thermald stop mpdecision stop thermal-engine # online A57 echo 1 ...
- 无刷新更新listview
闲来无事,写点水文吧!有用得着的可以参考下,无刷新更新listview是什么意思呢?举个例子,在订单类listview列表中,常常会有各种订单状态,拿商城类app来说,会有待付款,待收货,确认收货等等 ...
- UNIX网络编程——客户/服务器程序设计示范(总结)
(1)当系统负载较轻是,每来一个客户请求现场派生一个子进程为之服务的传统并发服务器程序模型就足够了.这个模型甚至可以与inetd结合使用,也就是inetd处理每个连接的接收.我们的其他意见是就重负荷运 ...
- 安卓banner图片轮播
之前写过一篇关于首页图片广告轮播的demo:http://blog.csdn.net/baiyuliang2013/article/details/45740091,不过图片轮播的指示器(小白点)处操 ...
- JavaI/O体系详解
Java中IO操作主要是指使用Java进行输入,输出操作,Java中所有的IO操作类都存放在Java.io包中,在使用时需要导入此包. 在整个Java.io包中最重要的就是5个类和一个接口.5个类指的 ...
- IBM SPSS 实习总结
2015过完年,我知道导师要出国了,自己也算是水了一个idea 的论文.希望研二能找个实习,早听说西安IBM这边有学长在里面实习过,2月底联系了一下简历就塞了过去.面试就在锦业一路软件园他们上班的地方 ...
- A*寻路算法入门(六)
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交流 ...