数据结构顺序表

初次尝试了c++类模板,来完成顺序表

//.h文件
template <typename T>
class SeqList {
private:
    T* arr;
    int capacity;
    int size;
public:
    SeqList();
    SeqList(T* arr, int size);
    SeqList(const SeqList<T>& sl);
    ~SeqList();
    void PushBack(T data);          //尾插
    void PopBack();                 //尾删
    void PushFront(T data);         //头插
    void PopFront();                //头删
    void Insert(int pos, T data);   //任意位置插入
    void Erase(int pos);            //任意位置删除
    bool Empty();                   //检测顺序表是否为空
    bool Find(T data);              //检测data是否在顺序表中
    void Remove(T data);        //移除顺序表中第一个值为data的元素
    void RemoveAll(T data);     //移除顺序表中所有值为data的元素
    int getSize() {             //获取顺序表有效元素个数
        return size;
    }
    int getCapacity() {         //获取顺序表的容量
        return capacity;
    }
    T getFront() {              //获取顺序表中第一个元素
        return arr[0];
    }
    T getBack() {               //获取顺序表中最后一个元素
        return arr[size - 1];
    }
    SeqList& operator=(const SeqList& sl);
    T& operator[](int i);
    template<typename T>
    friend std::ostream& operator<<(std::ostream& os, const SeqList<T>& sl);
};
  • 遇到的第一个问题,就是默认构造函数和析构函数报错:error LNK2019: 无法解析的外部符号 “public: void __thiscall…
    原因是类模板的.cpp文件链接时出了问题,具体原因这里就不讲了,感兴趣可以自行查找,在网上找到的解决方法有两种
    1.使用export关键字,但我使用无果后查找原因,这个关键字vs和gcc都不支持,这个功能在c++17就移除了,现在关键字还保留着,今后可能会赋予新的功能。
    2.另一种解决思路有多种方法,可以将类函数的实现和类声明一起写在.h文件中,或者.h和.cpp分开写,在.h的声明后面加上#include”.cpp" ,还可以选择在使用类模板的文件中#include".cpp"
//.cpp文件
//默认构造函数
template<typename T>
SeqList<T>::SeqList() {
    arr = new T[10];
    size = 0;
    capacity = 10;
}

template<typename T>
SeqList<T>::SeqList(T * arr, int size) {
    this->arr = new T[size];
    this->size = size;
    this->capacity = 2 * size;
    for (int i = 0; i < size; ++i) {
        this->arr[i] = arr[i];
    }
}

//复制构造函数
template<typename T>
SeqList<T>::SeqList(const SeqList<T>& sl) {
    this->arr = new T[sl.capacity];
    this->size = sl.size;
    this->capacity = sl.capacity;
    for (int i = 0; i < sl.size; ++i) {
        this->arr[i] = sl.arr[i];
    }
}

//析构函数
template<typename T>
SeqList<T>::~SeqList() {
    delete[] arr;
}

//然后是顺序表的一些功能实现,较为简短的已经在声明中隐式内联实现了
template<typename T>
void SeqList<T>::PushBack(T data) {
    if (size == capacity) {
        T* tmp = arr;
        arr = new T[capacity * 2];
        capacity *= 2;
        for (int i = 0; i < size; ++i) {
            arr[i] = tmp[i];
        }
        delete[] tmp;
    }
    arr[size] = data;
    ++size;
}

template<typename T>
void SeqList<T>::PopBack() {
    --size;
}

template<typename T>
void SeqList<T>::PushFront(T data) {
    if (size == capacity) {
        T* tmp = arr;
        arr = new T[capacity * 2];
        capacity *= 2;
        for (int i = 0; i < size; ++i) {
            arr[i] = tmp[i];
        }
        delete[] tmp;
    }
    for (int i = size; i > 0; --i) {
        arr[i] = arr[i - 1];
    }
    arr[0] = data;
    ++size;
}

template<typename T>
void SeqList<T>::PopFront() {
    for (int i = 0; i < size - 1; ++i) {
        arr[i] = arr[i + 1];
    }
    --size;
}

//添加元素时的动态扩容也可以封装成一个private成员函数,使代码更简洁
template<typename T>
void SeqList<T>::Insert(int pos, T data) {
    if (size == capacity) {
        T* tmp = arr;
        arr = new T[capacity * 2];
        capacity *= 2;
        for (int i = 0; i < size; ++i) {
            arr[i] = tmp[i];
        }
        delete[] tmp;
    }
    if (pos >= size || pos < 0) {
        arr[size] = data;
    }
    else {
        for (int i = size; i > pos; --i) {
            arr[i] = arr[i - 1];
        }
        arr[pos] = data;
    }
    ++size;
}

template<typename T>
void SeqList<T>::Erase(int pos) {
    if (pos >= 0 && pos < size) {
        for (int i = pos; i < size - 1; ++i) {
            arr[i] = arr[i + 1];
        }
        --size;
    }
}

bool SeqList<T>::Empty() {
    if (size == 0) {
        return true;
    }
    else {
        return false;
    }
}

template<typename T>
bool SeqList<T>::Find(T data) {
    for (int i = 0; i < size; ++i) {
        if (arr[i] == data) {
            return true;
        }
    }
    return false;
}

template<typename T>
void SeqL/ist<T>::Remove(T data) {
    for (int i = 0; i < size; ++i) {
        if (arr[i] = data) {
            Erase(i);
            return;
        }
    }
}

template<typename T>
void SeqList<T>::RemoveAll(T data) {
    for (int i = 0; i < size; ++i) {
        if (arr[i] == data) {
            Erase(i);
            continue;
        }
    }
}

//这里一定要定义自己的赋值运算符重载函数,否则默认生成的复制函数只会复制成员的值,
//使两个对象中的指针指向同一块内存空间,当一个对象析构后,另一个析构时就会重复delete一段空间第二次
template<typename T>
SeqList<T>& SeqList<T>::operator=(const SeqList<T>& sl) {
    if (this != &sl) {
        delete[] this->arr;
        this->arr = new T[sl.capacity];
        this->size = sl.size;
        this->capacity = sl.capacity;
        for (int i = 0; i < sl.size; ++i) {
            this-/>arr[i] = sl.arr[i];
        }
    }
    return *this;
}

//重载 [ ] 让顺序表使用更加方便
template<typename T>
T & SeqList<T>::operator[](int i) {
    return this->arr[i];
}

//用于cout的<<需要重载为友元函数才能按下面的顺序接受参数从而实现连续输出,但类模板的友元函数需要在声明时加上template<typename T>,
//否则无法与类一同成为模板。因为它不是类的成员却要使用const SeqList<T> & sl 为参数,编译器不知道<T>到底该是什么
template<typename T>
std::ostream & operator<<(std::ostream & os, const SeqList<T> & sl) {
    for (int i = 0; i < sl.size; ++i) {
        os << sl.arr[i] << "  ";
    }
    return os;
}

如有问题欢迎留言指出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值