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. java使用poi包将数据写入Excel表格

    1.Excel相关操作代码 import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundExcept ...

  2. Blog 公用部分结构与class定义

    /*博客文章公用部分class与结构 common*/ /* 1.title-block //标题块 ├── border-danger //危险红 ├── border-info //普通蓝 └── ...

  3. 代码阅读分析工具Understand 2.0试用

    Understand 2.0是一款源代码阅读分析软件,功能强大.试用过一段时间后,感觉相当不错,确实可以大大提高代码阅读效率.由于Understand功能十分强大,本文不可能详尽地介绍它的所有功能,所 ...

  4. WebApi接口传参不再困惑(4):传参详解(转载)

    WebApi接口传参不再困惑(4):传参详解   前言:还记得刚使用WebApi那会儿,被它的传参机制折腾了好久,查阅了半天资料.如今,使用WebApi也有段时间了,今天就记录下API接口传参的一些方 ...

  5. Find Missing Term in Arithmetic Progression 等差数列缺失项

    查找等差数列中的缺失项. e.g.Input: arr[] = {2, 4, 8, 10, 12, 14} Output: 6 Input: arr[] = {1, 6, 11, 16, 21, 31 ...

  6. DEDE有无缩略图如何调取

    同一样式分开调取 [field:array runphp='yes']@me = (strpos(@me['litpic'],'defaultpic') ? "":"&l ...

  7. 零基础学WEB前端-CSS

    CSS指层叠样式表(Cascading Style Sheets),CSS 是标准的布局语言,用来控制元素的尺寸.颜色.排版.CSS 由 W3C 发明,用来取代基于表格的布局.框架以及其他非标准的表现 ...

  8. 使用Canvas绘制背景图

    原文  http://www.imququ.com/post/use-canvas-as-background-image.html 最近iCloud Web的Beta版换了UI,整体风格变得和iOS ...

  9. C#写入日志信息到文件中

    为了在服务器上运行程序及时的跟踪出错的地方,可以在必要的地方加入写日志的程序. string folder = string.Format(@"D:\\{0}\\{1}", Dat ...

  10. ios 控件显示不出来的几个可能