C++模拟实现JDK中的ArrayList和LinkedList

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

声明Collection接口:

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

#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) = 0;
    virtual T* get(int index) = 0;
    virtual T* remove(int index) = 0;
};

#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 = 10> // bsz代表每次扩展数组的步长
class ArrayList: public List<T> { // 继承List和Collection
    int len; // 已使用量
    int max; // 最大长度
    T** items;
    void inflate(); // 扩充数组
    ArrayList(const ArrayList&); // 处于使用习惯隐藏拷贝函数,用户只能通过引用或指针
public:
    ArrayList() :
            len(0), 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(0) {
        }
        bool hasNext() {
            if (index < al.len) {
                return true;
            }
            return false;
        }
        T* next() {
            if (hasNext()) {
                return al.items[index++];
            }
            return 0;
        }
    };
};
/**
 * 以下是实现,如果处于效率考虑。有些函数可以增加inline。
 */
template<class T, int bsz>
ArrayList<T, bsz>::~ArrayList() {
    for (int i = 0; i < len; i++) {
        delete items[i];
        items[i] = 0; // 清理对象
    }
    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 = 0; 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 = 0; i < len; i++) {
        if (get(i) == e) {
            return i; // 返回下标
        }
    }
    return -1;
}
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 != -1) {
        remove(index);
        return true;
    }
    return false;
}
template<class T, int bsz>
bool ArrayList<T, bsz>::isEmpty() { // 判断容器是否为空
    if (len == 0) {
        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 = 0; i < len; i++) {
        if (i < index) {
            newItems[i] = items[i];
        }
        if (i == index) {
            newItems[i] = e;
        }
        if (i > index) {
            newItems[i] = items[i - 1];
        }
    }
    items = newItems;
}
template<class T, int bsz>
T* ArrayList<T, bsz>::get(int index) { // 获取元素
    if (index < 0 || index >= len) {
        return 0;
    }
    return items[index];
}
template<class T, int bsz>
T* ArrayList<T, bsz>::remove(int index) { // 删除元素
    if (index < 0 || index >= len) {
        return 0;
    }
    T* result = get(index);
    T* newItems[len - 1];
    for (int i = 0; i < len; i++) {
        if (i < index) {
            newItems[i] = items[i];
        }
        if (i > index) {
            newItems[i - 1] = 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 = 0, Item* pre = 0) : // 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(0), head(0), tail(0) {
    }
    virtual ~LinkedList() {
        if (len != 0) {
            while (head->next != 0) {
                Item* item = head;
                head = item->next;
                delete item;
                item = 0;
            }
        }
    }
    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(0) {
        }
        bool hasNext() {
            if (index < ll.len) {
                return true;
            }
            return false;
        }
        T* next() {
            if (hasNext()) {
                return ll.get(index++);
            }
            return 0;
        }
    };
};
/**
 * 以下为实现
 */
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 = 0; i < len; i++) {
        if (temp->data == e) {
            return i;
        }
        temp = temp->next;
    }
    return -1;
}
template<class T>
bool LinkedList<T>::isEmpty() {
    if (len == 0) {
        return true;
    } else {
        return false;
    }
}
template<class T>
bool LinkedList<T>::remove(T* e) {
    int index = contains(e);
    if (index != -1) {
        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 > 0 || index <= len) {
        if (len == 0) { // 第一个对象加入的时候,head引用和tail引用指向同一个
            Item* first = new Item(e);
            head = first;
            tail = first;
        } else if (index == 0) { // 如何插入第一个位置,则更新head引用
            Item* temp = new Item(e, head, 0);
            head->prev = temp;
            head = temp;
        } else if (index == len) { // 如果插入最后一个位置,则更新tail引用
            Item* temp = new Item(e, 0, tail);
            tail->next = temp;
            tail = temp;
        } else { // 更新中间元素
            Item* itemPrev = head;
            for (int i = 1; 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 >= 0 || index < len) {
        Item* result = head;
        for (int i = 0; i < index; i++) {
            result = result->next;
        }
        return result->data;
    }
    return 0;
}
template<class T>
T* LinkedList<T>::remove(int index) {
    if (index > 0 || index <= len) {
        if (index == 0) { // 删除head引用
            Item* temp = head;
            head = temp->next;
            head->prev = 0;
            T* result = temp->data; // 建立指向返回值的指针。
            delete item;
            item = 0;
            return result;
        } else if (index == len) { // 删除tail引用
            Item* temp = tail;
            tail = temp->prev;
            tail->next = 0;
            T* result = temp->data;
            delete item;
            item = 0;
            return result;
        } else {
            Item* item = head;
            for (int i = 0; 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 = 0;
            return result;
        }
        len--;
    }
    return 0;
}

#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 = 0; i < 15; i++) {
        int* v = new int(i);
        ia.add(v);
    }
    cout << ia.size() << endl;
    for (int i = 0; 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 = 0; i < sa.size(); i++) {
        cout << *sa.get(i) << endl;
    }
    in.close();

    // 测试LinkedList<int>
    LinkedList<int> il;
    for (int i = 0; i < 33; i++) {
        il.add(new int(i));
    }
    for (int i = 0; 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 = 0; 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;
    }
}

 

posted @ 2016-11-23 13:05  冷豪  阅读(1613)  评论(0编辑  收藏  举报