笔记四:线性表——数组描述

线性表

  • 定义:有序表,元素按照一定顺序形成的有序集合

  • 数组描述的线性表:

    1、代码:

#pragma warning(disable:4996)

#include<iostream>
#include<iterator>
#include<algorithm>
using namespace std;

typedef struct{
    int a;
    int b;
} Mytype;

template<typename T>
class linearList
{
public:
    virtual ~linearList() {};                  //析构函数
    virtual bool empty() const = 0;         //返回true,当且仅当线性表为空
    virtual int size() const = 0;           //返回线性表的元素个数
    virtual T& get(int theIndex) const = 0; //返回索引为theIndex的元素
    virtual int indexOf(const T& theElement) const = 0;         //返回元素theElement第一次出现时的索引
    virtual void erase(int theIndex) = 0;                       //删除索引为theIndex的元素
    virtual void insert(int theIndex, const T& theElement) = 0; //把theElement插入线性表中索引为theIndex的位置
    virtual void output(ostream& out) const = 0;                //把线性表插入的输出流out
};

template<typename T>
class arrayList : public linearList<T>
{
public:
    //构造函数、复制构造函数、析构函数
    arrayList(int initialCapacity = 10);
    arrayList(const arrayList<T>&);
    ~arrayList() { delete[] element; }

    //ADT方法
    bool empty() const;
    int size() const;
    T& get(int theIndex) const;
    int indexOf(const T& theElement) const;
    void erase(int theIndex);
    void insert(int theIndex, const T& theElement);
    void output(ostream& out) const;

public:
    void changeLength1D(T*& a, int oldLength, int newLength);
    friend ostream& operator<<(ostream& out, const arrayList<T>& x);
    void checkIndex(int theIndex) const;

private:
    int listSize;   //线性表的元素个数
    int arrayLength;    //一维数组的容量
    T*  element;    //存储线性表元素的一维数组
};

template<typename T> arrayList<T>::arrayList(int initialCapacity)
{//构造函数
    arrayLength = initialCapacity;
    element = new T[arrayLength];
    listSize = 0;
}

template<typename T> arrayList<T>::arrayList(const arrayList<T>& theList)
{//复制构造函数
    arrayLength = theList.arrayLength;
    listSize = theList.listSize;
    element = new T[arrayLength];
    copy(theList.element, theList.element + listSize, element);
}

template<typename T> bool arrayList<T>::empty() const
{
    return (listSize  ==  0 ? true : false);
}

template<typename T> int arrayList<T>::size() const
{
    return listSize;
}

template<typename T> T& arrayList<T>::get(int theIndex) const
{
    checkIndex(theIndex);
    return element[theIndex];   
}

template<typename T> int arrayList<T>::indexOf(const T& theElement) const
{
    //指向theElement的指针与数组首指针的差值
    int theIndex = (int)(find(element, element + listSize, theElement) - element);  
    return (theIndex == listSize ? -1 : theIndex);
}

template<typename T> void arrayList<T>::erase(int theIndex)
{
    checkIndex(theIndex);
    //将theIndex后面的元素依次前移一位,通过占据theIndex元素的位置将其覆盖
    copy(element + theIndex + 1, element + listSize, element + theIndex);
    element[--listSize].~T();  //删除最后一个元素,避免重复
}

template<typename T> void arrayList<T>::insert(int theIndex, const T& theElement)
{
    //theIndex不合法
    if (theIndex <0 || theIndex > listSize)
    {
        cout << "元素插入的theIndex下标不合理! ";
        exit(-1);
    }

    //有效索引,判断数组是否已满
    if (listSize == arrayLength)
    {
        //增加数组容量
        changeLength1D(element, arrayLength, arrayLength * 2);
        arrayLength = arrayLength * 2;  //修改数组容量值
    }

    copy_backward(element + theIndex, element + listSize, element + listSize + 1);
    element[theIndex] = theElement;
    ++listSize;
}

template<typename T> void arrayList<T>::changeLength1D(T*& a, int oldLength, int newLength)
{
    //判断新的容量是否合法
    if (newLength < 0)
    {
        cout << "错误:newLength 小于 0!";
        exit(-1);
    }

    T *tmp = new T[newLength];
    int number = min(oldLength, newLength); //复制的元素的数量判断
    copy(a, a + number, tmp);   //元素复制
    a = tmp;    
}


template<typename T> ostream& operator<<(ostream& out, const arrayList<T>& x)
{
    x.output(out);
    return out;
}

template<typename T> void arrayList<T>::output(ostream& out) const
{
    //把线性表插入输出流
    copy(element, element + listSize,  ostream_iterator<T>(cout, " "));
}

template<typename T> void arrayList<T>::checkIndex(int theIndex) const
{
    if (theIndex < 0 || theIndex >= listSize)
    {
        cout << "错误:theIndex 不合法!";
        exit(-1);
    }
}



int main(int argc, char * argv[])
{


    arrayList<int> aL(10);

    //测试insert函数
    aL.insert(0, 5);
    aL.insert(1, 4);
    aL.insert(2, 3);
    aL.insert(3, 2);
    aL.insert(4, 1);

    //测试output函数 
    cout << "初始线性表为:";
    aL.output(cout);
    cout << endl;
    cout << "初始线性表的大小为:" << aL.size()<<endl;

    //测试erase函数
    cout << "删除theIndex = 2的元素后线性表为:";
    aL.erase(2);
    aL.output(cout);
    cout << "     大小size: " << aL.size() << endl;

    //测试insert函数
    aL.insert(0, 0);
    cout << "在theIndex = 0的位置插入元素0后,线性表为:";
    aL.output(cout);
    cout << "     大小size: " << aL.size() << endl;

    //测试indexOf函数
    cout << "元素值为5的下标是:" << aL.indexOf(5) << endl;

    //测试get函数
    cout << "下标为1的元素是:" << aL.get(1) << endl;

    return 0;
}

2、运行:

这里写图片描述

  • 扩展:

    • 纯虚函数:为后代类型提供了可以覆盖的接口、但是该类中的版本绝不会调用,且不允许创建对象。在函数形参表后面写上 = 0 用以指定纯虚函数。virtual fun() = 0 ;

    • 抽象基类:含有(或继承)一个或多个纯虚函数的类。不能创建实例对象。

    • 重载操作符
      1、重载操作符必须具有一个类类型或枚举类型的操作数。
      2、一般将算数和关系操作符定义为非成员函数,而将赋值操作符定义为成员函数.
      3、作为类成员的重载函数,其形参比操作数目少1,因为第一个操作数为隐含的this形参Sale_item& operator+=(const Sale_item&);
      4、操作符定义为非成员函数时,通常设置为友元friend ostream& operator<<(ostream& out, const arrayList<T>& x);

    • 构造函数与复制构造函数
      1、构造函数:保证每个对象的数据成员具有合适的初始值A::A(const int& x) : a(0), b(x) {};
      2、复制构造函数:只有单个形参,且该形参是对本类类型的引用(常用const修饰)。

    • 析构函数与虚析构函数
      1、析构函数:完成所需的资源回收,作为类构造函数的补充。析构函数无法重载。
      2、许多类不需要显示析构函数,尤其是具有构造函数的类不一定要定义自己的构造函数。如果类需要析构函数,则它也需要赋值操作符和复制构造函数——三法则。
      3、动态分配的内存只有在指向该对象的指针被删除时才撤销,如果没有删除指向动态对象的指针,则不会运行该对象的析构函数,对象就一直存在,从而导致内存泄露。
      4、赋值操作符:1)重载的赋值操作符Sale_item& operator=(const Sale_item&);,2)合成赋值操作符——逐个成员赋值。
      5、赋值操作符与复制构造函数的调用区别:如果对象在声明的同时,将一个已存在的对象赋值给它,则调用复制构造函数;如果对象已经存在,再将另一个已存在的对象赋给它,则调用赋值操作符。
      3、虚析构函数:如果删除基类指针,则需运行基类析构函数,若对象是派生类型,则不需要定义该行为。为了保证运行适当的析构函数,基类中的析构函数必须为虚析构函数。(即使析构函数没有工作要做,继承层次的根类也应该定义一个虚析构函数。

    • copy()与copy_backward(): copy()函数实现元素左移功能,copy_backward()实现元素右移功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值