Java实现ArrayList和LinkedList的方式采用的是数组和链表。以下是用C++代码的模拟:

声明Collection接口:

#ifndef COLLECTION_H_
#define COLLECTION_H_
template<class T>
class Collection {
public:
virtual ~Collection() {
}
virtual bool add(T* e) = ;
virtual int contains(T* e) = ;
virtual bool isEmpty() = ;
virtual bool remove(T* e) = ;
virtual int size() = ;
}; #endif /* COLLECTION_H_ */

声明List接口

#ifndef LIST_H_
#define LIST_H_
#include "Collection.h"
template<class T>
class List: public Collection<T> {
public:
virtual ~List() {
}
virtual void add(int index, T* e) = ;
virtual T* get(int index) = ;
virtual T* remove(int index) = ;
}; #endif /* LIST_H_ */

接口声明完成以后就是具体实现。通过C++的模板来模拟Java中的泛型机制,通过嵌套Iterator类实现各自的迭代器。由于在Java中Iterator最常用的方法是hasNext()和next()。因此本文只做了这两个方法的实现。

ArrayList.h

#ifndef ARRAYLIST_H_
#define ARRAYLIST_H_
#include "List.h"
template<class T, int bsz = > // bsz代表每次扩展数组的步长
class ArrayList: public List<T> { // 继承List和Collection
int len; // 已使用量
int max; // 最大长度
T** items;
void inflate(); // 扩充数组
ArrayList(const ArrayList&); // 处于使用习惯隐藏拷贝函数,用户只能通过引用或指针
public:
ArrayList() :
len(), max(bsz), items(new T*[bsz]) {
}
virtual ~ArrayList();
bool add(T* e); // 增加元素
int contains(T* e); // 判断是否包含
bool isEmpty(); // 判断容器是否为空
bool remove(T* e); // 移除元素
int size(); // 获取容器容量
void add(int index, T* e); // 增加元素
T* get(int index); // 获取元素
T* remove(int index); // 删除元素
class Iterator;
friend class Iterator;
class Iterator { // 创建迭代器
ArrayList& al;
int index;
public:
Iterator(ArrayList& list) :
al(list), index() {
}
bool hasNext() {
if (index < al.len) {
return true;
}
return false;
}
T* next() {
if (hasNext()) {
return al.items[index++];
}
return ;
}
};
};
/**
* 以下是实现,如果处于效率考虑。有些函数可以增加inline。
*/
template<class T, int bsz>
ArrayList<T, bsz>::~ArrayList() {
for (int i = ; i < len; i++) {
delete items[i];
items[i] = ; // 清理对象
}
delete items; // 清空数组
}
template<class T, int bsz>
void ArrayList<T, bsz>::inflate() {
if (len == max) {
max += bsz; // 数组增加并且赋值保存的指针
T** newItems = new T*[max];
for (int i = ; i < len; i++)
newItems[i] = items[i];
delete[] items; // 清空原始数组:这里很重要!如果不清理会多出很多匿名数组占用内存。
items = newItems;
}
}
template<class T, int bsz>
bool ArrayList<T, bsz>::add(T* e) {
inflate();
items[len++] = e;
return true;
}
template<class T, int bsz>
int ArrayList<T, bsz>::contains(T* e) { // 判断是否包含:判断是否相同的标准是两个对象指针是否指向同一块内存。
for (int i = ; i < len; i++) {
if (get(i) == e) {
return i; // 返回下标
}
}
return -;
}
template<class T, int bsz>
int ArrayList<T, bsz>::size() { // 获取容器容量
return len;
}
template<class T, int bsz>
bool ArrayList<T, bsz>::remove(T* e) { // 调用内部的两个函数组合作为实现
int index = contains(e);
if (index != -) {
remove(index);
return true;
}
return false;
}
template<class T, int bsz>
bool ArrayList<T, bsz>::isEmpty() { // 判断容器是否为空
if (len == ) {
return true;
} else {
return false;
}
}
template<class T, int bsz>
void ArrayList<T, bsz>::add(int index, T* e) { // 增加元素:插入
inflate();
T* newItems[++len];
index--; // 下标
for (int i = ; i < len; i++) {
if (i < index) {
newItems[i] = items[i];
}
if (i == index) {
newItems[i] = e;
}
if (i > index) {
newItems[i] = items[i - ];
}
}
items = newItems;
}
template<class T, int bsz>
T* ArrayList<T, bsz>::get(int index) { // 获取元素
if (index < || index >= len) {
return ;
}
return items[index];
}
template<class T, int bsz>
T* ArrayList<T, bsz>::remove(int index) { // 删除元素
if (index < || index >= len) {
return ;
}
T* result = get(index);
T* newItems[len - ];
for (int i = ; i < len; i++) {
if (i < index) {
newItems[i] = items[i];
}
if (i > index) {
newItems[i - ] = items[i];
}
}
delete items;
items = newItems;
len--;
return result;
}
#endif /* ARRAYLIST_H_ */

很明显,和Java中的ArrayList实现一样。进行插入的代价是很高的。

LinkedList.h

#ifndef LINKEDLIST_H_
#define LINKEDLIST_H_
#include "List.h"
#include <iostream>
using namespace std;
template<class T>
class LinkedList: public List<T> {
struct Item { // 链表结构
Item(T* d, Item* nxt = , Item* pre = ) : // d:保存数据,nxt:指向前一个链表结构,pre:指向下一个链表结构。
data(d), next(nxt), prev(pre) {
}
T* data;
Item* next;
Item* prev;
};
int len; // 长度
Item* head; // 链表的头指针
Item* tail; // 链表的尾指针
LinkedList(const LinkedList&); // 隐藏拷贝函数
public:
LinkedList() :
len(), head(), tail() {
}
virtual ~LinkedList() {
if (len != ) {
while (head->next != ) {
Item* item = head;
head = item->next;
delete item;
item = ;
}
}
}
bool add(T* e); // 增加元素
int contains(T* e); // 判断是否包含
bool isEmpty(); // 判断容器是否为空
bool remove(T* e); // 删除元素
int size(); // 获取容器容量
void add(int index, T* e); // 增加元素
T* get(int index); // 获取元素
T* remove(int index); // 删除元素
class Iterator;
friend class Iterator;
class Iterator {
LinkedList& ll;
int index;
public:
Iterator(LinkedList& list) :
ll(list), index() {
}
bool hasNext() {
if (index < ll.len) {
return true;
}
return false;
}
T* next() {
if (hasNext()) {
return ll.get(index++);
}
return ;
}
};
};
/**
* 以下为实现
*/
template<class T>
bool LinkedList<T>::add(T* e) { // 入栈操作
add(len, e);
return true;
}
template<class T>
int LinkedList<T>::contains(T* e) {
Item* temp = head;
for (int i = ; i < len; i++) {
if (temp->data == e) {
return i;
}
temp = temp->next;
}
return -;
}
template<class T>
bool LinkedList<T>::isEmpty() {
if (len == ) {
return true;
} else {
return false;
}
}
template<class T>
bool LinkedList<T>::remove(T* e) {
int index = contains(e);
if (index != -) {
remove(index);
return true;
}
return false;
}
template<class T>
int LinkedList<T>::size() {
return len;
}
template<class T>
void LinkedList<T>::add(int index, T* e) { // 插入
if (index > || index <= len) {
if (len == ) { // 第一个对象加入的时候,head引用和tail引用指向同一个
Item* first = new Item(e);
head = first;
tail = first;
} else if (index == ) { // 如何插入第一个位置,则更新head引用
Item* temp = new Item(e, head, );
head->prev = temp;
head = temp;
} else if (index == len) { // 如果插入最后一个位置,则更新tail引用
Item* temp = new Item(e, , tail);
tail->next = temp;
tail = temp;
} else { // 更新中间元素
Item* itemPrev = head;
for (int i = ; i < index; i++) {
itemPrev = itemPrev->next;
}
Item* itemNext = itemPrev->next;
Item* newItem = new Item(e, itemNext, itemPrev);
itemPrev->next = newItem;
itemNext->prev = newItem;
}
len++;
}
}
template<class T>
T* LinkedList<T>::get(int index) { //
if (index >= || index < len) {
Item* result = head;
for (int i = ; i < index; i++) {
result = result->next;
}
return result->data;
}
return ;
}
template<class T>
T* LinkedList<T>::remove(int index) {
if (index > || index <= len) {
if (index == ) { // 删除head引用
Item* temp = head;
head = temp->next;
head->prev = ;
T* result = temp->data; // 建立指向返回值的指针。
delete item;
item = ;
return result;
} else if (index == len) { // 删除tail引用
Item* temp = tail;
tail = temp->prev;
tail->next = ;
T* result = temp->data;
delete item;
item = ;
return result;
} else {
Item* item = head;
for (int i = ; i < index; i++) { // 通过迭代获取目标指针
item = item->next;
}
Item* itemPrev = item->prev;
Item* itemNext = item->next;
itemPrev->next = itemNext;
itemNext->prev = itemPrev;
T* result = item->data;
delete item;
item = ;
return result;
}
len--;
}
return ;
} #endif /* LINKEDLIST_H_ */

LinkedList中所有的查询都必须依赖迭代完成,代价较高。但是插入的代价却比较低。这一点与JDK中的表现一致。

总结:

(1)C++的内存模型比Java复杂,因此可选择的余地也更多。本例程采用完全使用指针实现,基本等同于Java的实现方式。当然你也可以使用位拷贝的方式或&引用来做。有兴趣的可以自己摸索。

(2)C++中的垃圾清理需要手动完成,没有Java来的方便。虽然也提供了析构函数可以自行调用,但是通过观察例程很明显并非所有的工作都可以交给析构函数。更典型的做法是在函数内部随时清理。

如何使用:一个简单测试例程

#include "ArrayList.h"
#include "LinkedList.h"
#include <iostream>
#include <fstream>
using namespace std;
int main() {
// 测试ArrayList<int>
ArrayList<int> ia;
for (int i = ; i < ; i++) {
int* v = new int(i);
ia.add(v);
}
cout << ia.size() << endl;
for (int i = ; i < ia.size(); i++)
cout << *ia.get(i) << endl; // 测试ArrayList<string>
ArrayList<string> sa;
fstream in;
in.open("Main.cpp");
string line;
while (getline(in, line)) {
sa.add(new string(line));
}
for (int i = ; i < sa.size(); i++) {
cout << *sa.get(i) << endl;
}
in.close(); // 测试LinkedList<int>
LinkedList<int> il;
for (int i = ; i < ; i++) {
il.add(new int(i));
}
for (int i = ; i < il.size(); i++) {
cout << *il.get(i) << endl;
} // 测试LinkedList<string>
LinkedList<string> sl;
in.open("Main.cpp");
while (getline(in, line)) {
sl.add(new string(line));
}
for (int i = ; i < sl.size(); i++) {
cout << *sl.get(i) << endl;
}
in.close(); // 测试ArrayList<int>的迭代
ArrayList<int>::Iterator iat(ia);
while (iat.hasNext()) {
cout << *iat.next() << endl;
} // 测试ArrayList<string>的迭代
ArrayList<string>::Iterator ist(sa);
while (ist.hasNext()) {
cout << *ist.next() << endl;
} // 测试LinkedList<int>的迭代
LinkedList<int>::Iterator ilt(il);
while (ilt.hasNext()) {
cout << *ilt.next() << endl;
} // 测试LinkedList<string>的迭代
LinkedList<string>::Iterator slt(sl);
while (slt.hasNext()) {
cout << *slt.next() << endl;
}
}

C++模拟实现JDK中的ArrayList和LinkedList的更多相关文章

  1. 深入理解java中的ArrayList和LinkedList

    杂谈最基本数据结构--"线性表": 表结构是一种最基本的数据结构,最常见的实现是数组,几乎在每个程序每一种开发语言中都提供了数组这个顺序存储的线性表结构实现. 什么是线性表? 由0 ...

  2. JDK源代码学习-ArrayList、LinkedList、HashMap

    ArrayList.LinkedList.HashMap是Java开发中非常常见的数据类型.它们的区别也非常明显的,在Java中也非常具有代表性.在Java中,常见的数据结构是:数组.链表,其他数据结 ...

  3. List中的ArrayList和LinkedList源码分析

    ​ List是在面试中经常会问的一点,在我们面试中知道的仅仅是List是单列集合Collection下的一个实现类, List的实现接口又有几个,一个是ArrayList,还有一个是LinkedLis ...

  4. 27、ArrayList和LinkedList的区别

    在Java的List类型集合中,ArrayList和LinkedList大概是最常用到的2个了,细看了一下它们的实现,发现区别还是很大的,这里简单的列一下个人比较关心的区别. 类声明 ArrayLis ...

  5. [从今天开始修炼数据结构]线性表及其实现以及实现有Itertor的ArrayList和LinkedList

    一.线性表 1,什么是线性表 线性表就是零个或多个数据元素的有限序列.线性表中的每个元素只能有零个或一个前驱元素,零个或一个后继元素.在较复杂的线性表中,一个数据元素可以由若干个数据项组成.比如牵手排 ...

  6. Java 基础 - Collection集合通用方法及操作/ArrayList和LinkedList的差别优势 /弃用的Vector

    Collection的笔记: /**存储对象考虑使用: * 1.数组, ①一旦创建,其长度不可变!② 长度难于应对实际情况 * 2.Java集合, ①Collection集合: 1.set: 元素无序 ...

  7. 说说JDK中的List-ArrayList、Vector、LinkedList

    为方便开发人员,JDK提供了一套主要数据结构的实现,比如List.Map等.今儿说说List接口. List接口的一些列实现中,最常用最重要的就是这三个:ArrayList.Vector.Linked ...

  8. 【并发编程】Future模式及JDK中的实现

    1.1.Future模式是什么 先简单举个例子介绍,当我们平时写一个函数,函数里的语句一行行同步执行,如果某一行执行很慢,程序就必须等待,直到执行结束才返回结果:但有时我们可能并不急着需要其中某行的执 ...

  9. 13万字详细分析JDK中Stream的实现原理

    前提 Stream是JDK1.8中首次引入的,距今已经过去了接近8年时间(JDK1.8正式版是2013年底发布的).Stream的引入一方面极大地简化了某些开发场景,另一方面也可能降低了编码的可读性( ...

随机推荐

  1. mysql导入大文件sql

    备份mysqldump mysqldump -u root -p ao2012 > /mnt/www/zq_ao2012/backup.sql 然后数据库密码 导入 mysql -h local ...

  2. SpringBoot list查询方法

    SpringBoot中根据不同查询条件,获取list列表.@Componentpublic class QuerySpecifications {} (1)根据商户,查询商品全部列表 public S ...

  3. [bzoj2463]谁能赢呢

    我们通过观察可以发现,当n为偶数时,一定可以转化为一种先手必胜态,即棋盘可以被骨牌所覆盖, 如果n是奇数,那么去掉一格后一定能被1*2的骨牌覆盖,但是先手从左上角走,就进入了这个S态(必胜态),那么和 ...

  4. SqlServer触发器判断对表操作类型(增、删、改)并将修改后的数据映射到新表

    该文章为原创,日后可能会根据实际开发经验和网友评论,进行相应地方修改,为获得最新博客动态,望在转发博客的时候注明出处. 触发器要实现的功能: (1)获取对表Table1数据操作操作类型(insert. ...

  5. 由于某IP大频率提交评论导致服务器宕机

    早上突然收到dnspod的宕机通知(好久没收到了,有点手足无措). 服务器在上午10:40时达到85%.uptime显示cpu利用率达到35.不宕才怪. 按照之前的经验,应该是触发一个特别耗CPU的处 ...

  6. randow()方法

    Math库里的static(静态)方法random(),该方法的作用是产生0和1之间的一个double值. 注意产生的值包括0不包括1.

  7. Day 6

  8. Git tag push 到远端仓库

    很早之前,我们就提到过用Git tag来给工程打上标签,但是这个命令只是在本地仓库打标签而已, 为了能把标签同步到远程服务器,我们可以这样做: 默认情况下,git push并不会把tag标签传送到远端 ...

  9. mongodb学习(一)

    操作系统环境:ubuntu. 安装mongodb:apt-get install mongodb 安装后运行:mongod提示:[initandlisten] exception in initAnd ...

  10. node.js表单——formidable/////z

    node.js表单--formidable   node处理表单请求,需要用到formidable包.安装formidable包的命令如下: npm install formidable 安装pack ...