• 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;
        }
    }
  • 相关阅读:
    第二阶段冲刺报告(三)
    第二阶段冲刺报告(二)
    第二阶段冲刺报告(一)
    课程改进意见
    用户体验
    返回一个二维整数数组中最大联通子数组的和
    《你的灯亮着吗》阅读笔记三 ——谁的问题
    《你的灯亮着吗》阅读笔记二 ——什么是真正的问题
    《你的灯亮着吗》阅读笔记一 —— 问题是什么?
    我爱淘冲刺阶段站立会议2每天任务6
  • 原文地址:https://www.cnblogs.com/learnhow/p/6093247.html
Copyright © 2020-2023  润新知