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

  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. Spring之AOP模块

    AOP(Aspect Oriented Programming,面向切面编程)是Spring框架的一个重要特征 Spring推荐使用接口编程 Spring提供三种拦截器:方法前拦截器.返回后拦截器.异 ...

  2. GridView如何适配不同屏幕

    GridView和ListView一样,都是项目中常用的控件之一,那么本篇文章要讲的是GridView如何适应不同大小的屏幕,首先,我们来看一张效果图,如下: 每行为四个item,上下左右间距大概2d ...

  3. 19 Handler 子线程向主线程发送信息

    案例一 Message创建三种方法: package com.example.day19_handler_demo1; import android.os.Bundle; import android ...

  4. Android设置item的行间距,以及去掉分割线方法

    1.设置item的行间距: 可以在xml布局文件中的listView下设置xml属性: android:divider="#00000000" android:dividerHei ...

  5. ORACLE数据库学习之SQL性能优化详解

                                                                                    Oracle  sql 性能优化调整 ...

  6. FORM中调用JAVA组件

    调用方式: 链接:可以在一个数据块中创建专门的 Bean Area项,使用 Implementation Class 特性链接到J a v a B e a n,使用W h e n - C u s t ...

  7. 12 SharedPreferences

    SharedPreferences 创建方式 SharedPreferences preferences = getPreferences(Context context ,int mode); 参数 ...

  8. Android简易实战教程--第十话《模仿腾讯手机助手小火箭发射详解》

    之前对系统自带的土司的源码做了简要分析,见博客:点击打开链接 这一篇给一个小案例,自定义土司,模拟腾讯卫士的小火箭发射.如果想要迅速看懂代码,建议先去看一下上篇介绍点击打开链接 首先,定义一个服务,在 ...

  9. picasso图片缓存框架

    picasso是Square公司开源的一个Android图形缓存库,地址http://square.github.io/picasso/,可以实现图片下载和缓存功能. picasso使用简单,如下 [ ...

  10. 【翻译】在Ext JS 6通用应用程序中使用既共享又特定于视图的代码

    原文:Using Both Shared and View-Specific Code in an Ext JS 6 Universal App 在本文,在展示如何编写Ext JS 6通用应用程序代码 ...