"《算法导论》之‘线性表’":基于动态分配的数组的顺序表
我们利用静态分配的数组来实现的顺序表的局限还是挺大的,主要在于它的容量是预先定好的,用户不能根据自己的需要来改变。如果为了后续用户能够自己调整顺序表的大小,动态地分配数组空间还是很有必要的。基于动态分配的数组的顺序表绝大部分跟基于静态分配的数组的顺序表是一样的,只需在后者程序上改动一小部分即可。
第一,我们不需定义一个容量常量CAPACITY,而是定义一个私有变量myCapacity。
第二,类的构造函数需要改进一下。我们需要类在被实例化时自动申请内存,即需添加下边程序:
ElementType * seqList = new ElementType(myCapacity);
assert(seqList != NULL);
第三,类的析构函数需要添加下边一句:
delete [] seqList;
上面三点说的还有所欠缺。Larry Nyhoff在《数据结构与算法分析》第253页中提到设计类时要记住的一条规则:
如果类在运行时使用new分配内存,则它应该提供:
- 把动态分配的内存还给堆的析构函数。
- 编译器用来创建不同副本的复制构造函数。
- 程序员用来创建不同副本的赋值运算符。
基于动态分配的数组的顺序表设计的类如下:
// seqlist.h
#ifndef SEQLIST
#define SEQLIST #include <iostream>
#include <cassert>
#include <algorithm> using namespace std; typedef int ElementType; class SeqList
{
public:
SeqList(const int maxsize = );
virtual ~SeqList();
SeqList(const SeqList& origList); // 拷贝构造函数,记得防止浅拷贝
const SeqList& operator=(const SeqList& rightHandSide); // 重载赋值运算符,记得防止浅拷贝
bool empty() const;
void clear();
bool insert(const int pos, const ElementType val);
bool erase(const int pos);
void display() const;
bool setSeqList(const ElementType *tmpList, const int len);
int getLenOfList() const;
ElementType getItem(const int pos);
ElementType * getSeqList(); // 保留,不推荐使用,因为在使用过程中无法进行越界检查 private:
int myCapacity; // 自定义顺序表容量
int lenOfList; // 顺序表长度
ElementType * seqList; }; #endif
实现程序为:
// seqlist.cpp
#include <iostream>
#include <cassert>
#include "seqlist.h" using namespace std; SeqList::SeqList(const int maxsize)
{
// initialization
lenOfList = ;
myCapacity = maxsize;
seqList = new ElementType[myCapacity];
// assert(seqList != NULL);
if (seqList == NULL)
{
cerr << "Inadequate memory to allocate stack." << endl;
throw bad_alloc();
}
} SeqList::~SeqList()
{
delete[] seqList;
} SeqList::SeqList(const SeqList& origList)
{
myCapacity = origList.myCapacity;
lenOfList = origList.lenOfList;
seqList = new ElementType[myCapacity];
// assert(seqList != NULL);
if (seqList == NULL)
{
cerr << "Inadequate memory to allocate stack." << endl;
throw bad_alloc();
}
else
{
for (int i = ; i < lenOfList; i++)
{
seqList[i] = origList.seqList[i];
}
}
} const SeqList& SeqList::operator=(const SeqList& rightHandSide)
{
// 确保不是自我赋值
if (this != &rightHandSide)
{
// 如果需要,分配一个新数组
if (myCapacity != rightHandSide.myCapacity)
{
delete[] seqList;
myCapacity = rightHandSide.myCapacity;
seqList = new ElementType[myCapacity];
// assert(seqList != NULL);
if (seqList == NULL)
{
cerr << "Inadequate memory to allocate stack." << endl;
throw bad_alloc();
}
} lenOfList = rightHandSide.lenOfList;
for (int i = ; i < lenOfList; i++)
{
seqList[i] = rightHandSide.seqList[i];
}
}
return *this;
} bool SeqList::empty() const
{
return lenOfList == ;
} void SeqList::clear()
{
lenOfList = ;
fill(seqList, seqList + myCapacity - , );
} bool SeqList::insert(const int pos, const ElementType val)
{
bool success = false;
// assert(lenOfList != CAPACITY); // 这里的assert分成两行写,是为了方便定位错误发生的地方
// assert(0 <= pos <= lenOfList);
if (lenOfList == myCapacity)
{
cerr << "No space for insertion!" << endl;
}
else if (pos < || pos > lenOfList)
{
cerr << "The position " << pos <<
" you want to insert is less than zero or exceeds the length of the list!" << endl;
throw out_of_range("throw out_of_range"); // 抛出一个越界异常
}
else
{
int tmpCount = lenOfList - pos;
for (int i = ; i < tmpCount; i++)
{
seqList[lenOfList - i] = seqList[lenOfList - i - ];
}
seqList[pos] = val;
lenOfList++;
success = true;
}
return success;
} bool SeqList::erase(const int pos)
{
bool success = false;
// assert(lenOfList != 0);
// assert(0 <= pos <= lenOfList);
if (lenOfList == )
{
cerr << "There is no elements in the list!" << endl;
}
else if (pos < || pos > lenOfList)
{
cerr << "The position " << pos <<
" you want to erase is less than zero or exceeds the length of the list!" << endl;
throw out_of_range("throw out_of_range"); // 抛出一个越界异常
}
else
{
int tmp = lenOfList - pos;
for (int i = ; i < tmp - ; i++)
{
seqList[pos + i] = seqList[pos + i + ];
}
seqList[lenOfList - ] = ;
lenOfList--;
success = true;
}
return success;
} void SeqList::display() const
{
cout << "***Start Displaying***" << endl;
if (lenOfList == )
{
cerr << "There is no element in the the list!" << endl;
}
else
{
for (int i = ; i < lenOfList; i++)
{
cout << i << " : " << seqList[i] << endl;
}
cout << "***End Displaying***" << endl;
}
} bool SeqList::setSeqList(const ElementType *tmpList, const int len)
{
// assert(len <= CAPACITY);
bool success = false;
if (len <= myCapacity)
{
for (int i = ; i < len; i++)
{
seqList[i] = *(tmpList++);
}
lenOfList = len;
success = true;
}
else
{
cerr << "The length of the array you set exceeds the CAPACITY." << endl;
throw out_of_range("throw out_of_range"); // 抛出一个越界异常
}
return success;
} int SeqList::getLenOfList() const
{
return lenOfList;
} ElementType SeqList::getItem(const int pos)
{
// assert(0 <= pos <= lenOfList);
if (pos < || pos > lenOfList)
{
cerr << "The item at " << pos << " you want to get does not exist!" << endl;
throw out_of_range("throw out_of_range"); // 抛出一个越界异常
}
else
{
return seqList[pos];
}
} ElementType * SeqList::getSeqList()
{
return seqList;
}
seqlist.cpp
Boost单元测试程序为:
// BoostUnitTest.cpp
#define BOOST_TEST_MODULE ArrayList_Test_Module #include "stdafx.h"
#include "D:\VSProject\Algorithm\List\SeqList\SeqList_BsedOnDynamicArray\SeqList\seqlist.h" struct ArrayList_Fixture
{
ArrayList_Fixture()
{
BOOST_TEST_MESSAGE("Setup fixture");
testArrayList = new SeqList();
}
~ArrayList_Fixture()
{
BOOST_TEST_MESSAGE("Teardown fixture");
delete testArrayList;
} SeqList * testArrayList;
}; // BOOST_AUTO_TEST_SUITE(ArrayList_Test_Suite)
BOOST_FIXTURE_TEST_SUITE(ArrayList_Test_Suite, ArrayList_Fixture) BOOST_AUTO_TEST_CASE(ArrayList_Abnormal_Test)
{
// Set values to the array list
int testArray[] = { , , , , }; // 5 个元素
int testLenOfList = sizeof(testArray) / sizeof(int);
testArrayList->setSeqList(testArray, testLenOfList);
// BOOST_REQUIRE_THROW(testArrayList->setArrayList(testArray, testLenOfList), out_of_range); // Method getItem-----------------------------------------------
// If the position of the item you want to get is less than zero
BOOST_REQUIRE_THROW(testArrayList->getItem(-), out_of_range);
// If the position of the item you want to get is larger than the length of the list
BOOST_REQUIRE_THROW(testArrayList->getItem(), out_of_range); // Method insert-------------------------------------------------
// If the inserting position is less than zero
BOOST_REQUIRE_THROW(testArrayList->insert(-, ), out_of_range);
BOOST_REQUIRE(testArrayList->getLenOfList() == testLenOfList); // If the inserting position is larger than the length of the list
BOOST_REQUIRE_THROW(testArrayList->insert(, ), out_of_range);
BOOST_REQUIRE(testArrayList->getLenOfList() == testLenOfList); // Method erase-------------------------------------------------
// If the erasing position is less than zero
BOOST_REQUIRE_THROW(testArrayList->erase(-), out_of_range);
BOOST_REQUIRE(testArrayList->getLenOfList() == testLenOfList); // If the erasing position is larger than the length of the list
BOOST_REQUIRE_THROW(testArrayList->erase(), out_of_range);
BOOST_REQUIRE(testArrayList->getLenOfList() == testLenOfList); } BOOST_AUTO_TEST_CASE(ArrayList_Normal_Test)
{
bool expected;
bool actual;
// Method empty-------------------------------------------------
expected = true;
actual = testArrayList->empty();
BOOST_REQUIRE(expected == actual); // Set values to the array list
int testArray[] = { , , , , }; // 5 个元素
int testLenOfList = sizeof(testArray) / sizeof(int);
testArrayList->setSeqList(testArray, testLenOfList);
// BOOST_REQUIRE_THROW(testArrayList->setArrayList(testArray, testLenOfList), out_of_range); // Method getItem-----------------------------------------------
BOOST_REQUIRE(testArrayList->getItem() == testArray[]); // Method empty-------------------------------------------------
expected = false;
actual = testArrayList->empty();
BOOST_REQUIRE(expected == actual); // Method insert-------------------------------------------------
expected = true;
actual = testArrayList->insert(, );
BOOST_REQUIRE(expected == actual);
BOOST_REQUIRE(testArrayList->getLenOfList() == testLenOfList + );
BOOST_REQUIRE(testArrayList->getItem() == ); // Method erase-------------------------------------------------
expected = true;
actual = testArrayList->erase();
BOOST_REQUIRE(expected, actual);
BOOST_REQUIRE(testArrayList->getLenOfList() == testLenOfList);
BOOST_REQUIRE(testArrayList->getItem() == testArray[]); } BOOST_AUTO_TEST_CASE(ArrayList_CopyConstructor_Test)
{
bool expected;
bool actual;
// Set values to the array list
int testArray[] = { , , , , }; // 5 个元素
int testLenOfList = sizeof(testArray) / sizeof(int);
testArrayList->setSeqList(testArray, testLenOfList);
// BOOST_REQUIRE_THROW(testArrayList->setArrayList(testArray, testLenOfList), out_of_range); // Copy constructor
//SeqList * copySeqList(testArrayList); // 极容易写成这样子。错误。
// 需要给copySeqList分配内存
SeqList * copySeqList = new SeqList(*testArrayList); // Method getItem-----------------------------------------------
BOOST_REQUIRE(copySeqList->getItem() == testArray[]); // Method empty-------------------------------------------------
expected = false;
actual = copySeqList->empty();
BOOST_REQUIRE(expected == actual); // Method insert-------------------------------------------------
expected = true;
actual = copySeqList->insert(, );
BOOST_REQUIRE(expected == actual);
BOOST_REQUIRE(copySeqList->getLenOfList() == testLenOfList + );
BOOST_REQUIRE(copySeqList->getItem() == ); // Method erase-------------------------------------------------
expected = true;
actual = copySeqList->erase();
BOOST_REQUIRE(expected, actual);
BOOST_REQUIRE(copySeqList->getLenOfList() == testLenOfList);
BOOST_REQUIRE(copySeqList->getItem() == testArray[]);
} BOOST_AUTO_TEST_CASE(ArrayList_EqualOperator_Test)
{
bool expected;
bool actual;
// Set values to the array list
int testArray[] = { , , , , }; // 5 个元素
int testLenOfList = sizeof(testArray) / sizeof(int);
testArrayList->setSeqList(testArray, testLenOfList);
// BOOST_REQUIRE_THROW(testArrayList->setArrayList(testArray, testLenOfList), out_of_range); // Copy constructor
SeqList * copySeqList = new SeqList();
// copySeqList = testArrayList; // 极易犯的一个低级错误
*copySeqList = *testArrayList; // Method getItem-----------------------------------------------
BOOST_REQUIRE(copySeqList->getItem() == testArray[]); // Method empty-------------------------------------------------
expected = false;
actual = copySeqList->empty();
BOOST_REQUIRE(expected == actual); // Method insert-------------------------------------------------
expected = true;
actual = copySeqList->insert(, );
BOOST_REQUIRE(expected == actual);
BOOST_REQUIRE(copySeqList->getLenOfList() == testLenOfList + );
BOOST_REQUIRE(copySeqList->getItem() == ); // Method erase-------------------------------------------------
expected = true;
actual = copySeqList->erase();
BOOST_REQUIRE(expected, actual);
BOOST_REQUIRE(copySeqList->getLenOfList() == testLenOfList);
BOOST_REQUIRE(copySeqList->getItem() == testArray[]);
} BOOST_AUTO_TEST_SUITE_END();
BoostUnitTest.cpp
本篇博文的代码均托管到Taocode : http://code.taobao.org/p/datastructureandalgorithm/src/.
"《算法导论》之‘线性表’":基于动态分配的数组的顺序表的更多相关文章
- "《算法导论》之‘线性表’":基于静态分配的数组的顺序表
首先,我们来搞明白几个概念吧(参考自网站数据结构及百度百科). 线性表 线性表是最基本.最简单.也是最常用的一种数据结构.线性表中数据元素之间的关系是一对一的关系,即除了第一个和最后一个数据元素之外, ...
- C++利用动态数组实现顺序表(不限数据类型)
通过类模板实现顺序表时,若进行比较和遍历操作,模板元素可以通过STL中的equal_to仿函数实现,或者通过回调函数实现.若进行复制操作,可以采用STL的算法函数,也可以通过操作地址实现.关于回调函数 ...
- C语言利用动态数组实现顺序表(不限数据类型)
实现任意数据类型的顺序表的初始化,插入,删除(按值删除:按位置删除),销毁功能.. 顺序表结构体 实现顺序表结构体的三个要素:(1)数组首地址:(2)数组的大小:(3)当前数组元素的个数. //顺序表 ...
- 使用JAVA数组实现顺序表
1,引入了JAVA泛型类,因此定义了一个Object[] 类型的数组,从而可以保存各种不同类型的对象. 2,默认构造方法创建了一个默认大小为16的Object数组:带参数的构造方法创建一个指定长度的O ...
- 《算法导论》习题解答 Chapter 22.1-8(变换邻接表的数据结构)
一般散列表都与B+树进行比较,包括在信息检索中也是. 确定某条边是否存在需要O(1). 不足: (1)散列冲突. (2)哈希函数需要不断变化以适应需求. 另外:B+树.(见第18章) 与散列表相比的不 ...
- $Django 多对多-自定义第三张表 基于双下划线的跨表查询(补充)
自定义第三张表的好处:可以定义多个字段, 缺点:查询不方便(有方法解决) 1.第三张表设置外键,联合唯一(查询不方便) class Books(models.Model): name=models.C ...
- YTU 2989: 顺序表基本运算(线性表)
2989: 顺序表基本运算(线性表) 时间限制: 1 Sec 内存限制: 128 MB 提交: 1 解决: 1 题目描述 编写一个程序,实现顺序表的各种基本运算(假设顺序表的元素类型为char), ...
- C# 数据结构 线性表(顺序表 链表 IList 数组)
线性表 线性表是最简单.最基本.最常用的数据结构.数据元素 1 对 1的关系,这种关系是位置关系. 特点 (1)第一个元素和最后一个元素前后是没有数据元素,线性表中剩下的元素是近邻的,前后都有元素. ...
- 基于C++的顺序表的实现
顺序表,是数据结构中按顺序方式存储的线性表,又称向量.具有方便检索的特点.以下,是笔者学习是基于C++实现的顺序表代码,贴上来当网页笔记用. #include <iostream> usi ...
随机推荐
- RE模块错误已解决.
下面这个错误是由于在正则[...]的内部,减号'-'是一个有特殊含义的字符(代表字符范围) 所以如果需要在[...]内匹配减号'-',需要用反斜杠'\'转义. >>> import ...
- String放入运行时常量池的时机与String.intern()方法解惑
运行时常量池概述 Java运行时常量池中主要存放两大类常量:字面量和符号引用.字面量比较接近于Java语言层面的常量概念,如文本字符串.声明为final的常量值等. 而符号引用则属于编译原理方面的概念 ...
- Git运用基础之如何删除Github上不想要的项目
今天突然想删除,(强迫症想删除)之前练习时多创建的多个Github上的源代码或者无用Demo地址,然后看了一些文章都比较老式,这里我展示一下最新的删除步骤. 一.首先登录自己的Github账户主页(没 ...
- Struts 2 标签库
<s:if>标签 拥有一个test属性,其表达式的值用来决定标签里内容是否显示 <s:if test="#request.username=='clf'"> ...
- java中抽象类的定义和使用
java虽然比较简单,但是细节的知识点还是很多的,现在,介绍一下抽象类的定义和实现基础. 指的是在类中定义方法,而不去实现它,而在它的子类中去具体实现,继承抽象类的子类必须实现父类的抽象方法,除非子类 ...
- 剑指Offer——巧妙使用sort(List<T>,Comparator<? super T>)比较器
剑指Offer--巧妙使用sort(List<T>,Comparator<? super T>)比较器 先入为主 package cn.edu.ujn.offersword; ...
- 剑指Offer——京东校招笔试题+知识点总结
剑指Offer--京东校招笔试题+知识点总结 笔试感言 经过一系列的笔试,发觉自己的基础知识还是比较薄弱的,尤其是数据结构和网络,还有操作系统.工作量还是很大的.做到精确制导的好方法就是在网上刷题,包 ...
- 【一天一道Leetcode】#190.Reverse Bits
一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 我的个人博客已创建,欢迎大家持续关注! 一天一道le ...
- FFmpeg的H.264解码器源代码简单分析:解码器主干部分
===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...
- 使用Geolocation校正GDAL不支持的数据
对于低分数据来说,常用的校正方式就是给定数据的经纬度查找表来进行校正.在GDAL中,这种校正方式叫Geolocation array.常用的数据有国外的MODIS数据,国内的如风云系列(FY)和海洋系 ...