C++ 数据结构之顺序表

概念就不多讲了,直接上代码,仅供参考。

模板类:

#include <iostream>
using namespace std;
const int defaultSize = 100;
/*
*基类 顺序表
*/
template<class T>
class LinearList 
{
public:
	LinearList() {};  //构造函数
	~LinearList() {};   //析构函数
	 //const关键字表明该方法不能修改数据成员
	 //=0表示这是一个纯虚函数,必须由自己的继承类实现
	virtual int Size() const = 0;   //求表的最大长度
	virtual int Length() const = 0;  //求当前表的长度
	virtual int Search(T& x) const = 0;  //搜索给定值x在表中的位置
	virtual int Locate(int i) const = 0;  //在表中定位第i个元素的值
	virtual bool GetData(int i, T& x) const = 0;  //获取表中第i个表项
	virtual bool  SetData(int i, T& x) = 0;  //修改第i个表项为x
	virtual bool Insert(int i, T& x) = 0; //在第i个位置插入表项x;
	virtual bool Remove(int i, T& x) = 0; //移除第i个表项,返回值表示是否成功,x用来暂存删除的表项
	virtual bool IsEmpty() const = 0;//检查是否为空
	virtual bool IsFull() const = 0; //检查表是否已经满了
	virtual void Sort() = 0; //排序
	virtual void Input() = 0;  //接受输入
	virtual void Output() = 0; //输出
	//virtual LinearList<T> operator=(LinearList<T>& L) = 0;  //复制顺序表

};






//常量,不指定参数情况下顺序表的默认大小
template<class T>
class SeqList :public LinearList<T>
{
protected:
    T* data;  //指向T类型顺序表的指针
    int maxSize; //最大可以容纳的表项数
    int last;  //最后一个表项的下标,从0开始计数 last=length-1
    //改变data数组空间的大小,一般用于扩容,如果输入的参数小于last+1,可能导致数据丢失
   

public:
    SeqList(int sz = defaultSize);  //构造函数,默认长度为100
    SeqList(SeqList<T>& L);  //复制构造函数
    ~SeqList();  //析构函数
    int Size() const;  //容量查询函数
    int Length() const; //实际存储数据长度的查询函数
    int Search(T& x)const;  //在表中搜索x,并返回其位置
    int Locate(int i)const; //定位第i个表项,返回其表项序号
    bool GetData(int i, T& x)const; //获取第i个表项的值
    bool SetData(int i, T& x);  //用x的值取代第i个表项的值,使用返回值表示是否成功
    bool Insert(int i, T& x); //在第i个表项后面插入x
    bool Remove(int i, T& x); //移除第i个表项
    bool IsEmpty() const;  //判断表是否为空
    bool IsFull() const; //判断表是否满
    void Input();
    void Output();
    void Sort();
    void Add(T& x);
    void Swap(int a,int b);
    void Union( SeqList<T>& L2,SeqList<T>& res);  //并运算
    void Intersection(SeqList<T>& L2, SeqList<T>& res);  //交运算
    SeqList<T> operator=(SeqList<T>& L); //表整体赋值
    void Resize(int newSize);
    void ResizeDouble();  //默认情况下,将容量扩充为原来的一倍
private:
    template<class T>
    friend ostream& operator<<(ostream& out, SeqList<T>& list) ;
    template<class T>
    friend istream& operator>>(istream& out, SeqList<T>& list);
};

template<class T>
void SeqList<T>::Resize(int newSize)
{
    if (newSize < last + 1)  //安全校验,负数属于不合法数据,小于last+1,会造成数据丢失
    {
        cerr << "无效的数组大小" << endl;
        return;
    }
    T* newArray = new T[newSize];
    if (newArray == NULL)  //校验内存分配是否成功
    {
        cerr << "存储分配错误" << endl;
        exit(1);
    }
    int n = last + 1;
    T* srcPtr = data;  //原顺序表
    T* destPtr = newArray;//目标顺序表指针
    while (n--) {
        *destPtr++ = *srcPtr++;
        /*等价于
        *destPtr = *srcPtr;
        destPtr++;
        srcPtr++;
        */
    }
    delete[] data;
    data = newArray;
    maxSize = newSize;
}

template<class T>
void SeqList<T>::ResizeDouble()
{
    Resize(maxSize * 2);
}

//构造函数的具体实现
template<class T>
SeqList<T>::SeqList(int sz) {
    //除了在内部使用安全检查机制之外,也可以接受无符号整型作为参数
    if (sz > 0)   //检查输入的顺序表长度是否合法
    {
        maxSize = sz;
        last = -1;
        data = new T[maxSize];  //创建存储数组
        if (data == NULL)   //检查动态分配是否成功,一般情况都会成功
        {
            cerr << "内存分配出现错误" << endl;
            exit(1);
        }
    }
    else {                   //输入内容不合法,构造默认大小的数据空间
        maxSize = 100;
        last = -1;
        data = new T[maxSize];  
        if (data == NULL) 
        {
            cerr << "内存分配出现错误" << endl;
            exit(1);
        }
    }
}

//复制构造函数的具体实现
template<class T>
SeqList<T>::SeqList(SeqList<T>& L)
{
    maxSize = L.maxSize;
    last = L.Length() - 1;
    data = new T[maxSize];
    if (data == NULL)   //检查动态分配是否成功,一般情况都会成功
    {
        cerr << "内存分配出现错误" << endl;
        exit(1);
    }
    //逐一赋值
    for (int i = 1; i <= last + 1; i++)
    {
        T temp;
        //获取数值是根据数据的位置,从1开始计数,1---last+1
        L.GetData(i, temp);
        //根据下标进行赋值  0-last
        data[i - 1] = temp;
    }

}
//析构函数具体实现
template<class T>
SeqList<T>::~SeqList()
{
    delete[] data;   //将开辟的内存空间还给系统
}
//容量查询具体实现
template<class T>
int SeqList<T>::Size() const
{
    return maxSize;
}
//数据长度查询具体实现
template<class T>
int SeqList<T>::Length() const
{
    return last + 1;
}

template<class T>
int SeqList<T>::Search(T& x) const
{
    //返回值不是下标,是表项在表中的位置,从1开始
    //返回0表示该表中没有搜索到相同的表项
    for (int i = 0; i <= last; i++)  //遍历所有表项
    {
        if (data[i] == x)
        {
            return i + 1;
        }
    }
    return 0;
}

template<class T>
int SeqList<T>::Locate(int i) const
{
    //检查第i个表项是否存在
    if (i > 0 && i <= last + 1) {
        return i;
    }
    return 0; //表示第i个数据不存在
}

template<class T>
bool SeqList<T>::GetData(int i, T& x) const
{
    //安全校验,检查第i个数据是否存在,存在则保存在x中,否则返回false
    if (i > 0 && i <= last + 1) {
        x = data[i - 1];
        return true;
    }
    return false;
}

template<class T>
bool SeqList<T>::SetData(int i, T& x)
{
    //安全校验,检查第i个数据是否存在,存在则替换为x,否则返回false
    if (i > 0 && i <= last + 1) {
        data[i - 1] = x;
    }
    return false;
}

template<class T>
bool SeqList<T>::Insert(int i, T& x)
{
    //安全校验,表是否已满,满的情况下无法插入数据
    if (IsFull()) {
        return false;
    }
    //检查插入位置是否合理
    if (i<0 || i>last + 1)
    {
        //用1代表数据项,0代表可插入位置   010...10
        return false;
    }
    for (int j = last; j >= i; j--)
    {
        data[j + 1] = data[j];
    }
    data[i] = x;
    last++;//数据增加1个
    return true;
}

template<class T>
bool SeqList<T>::Remove(int i, T& x)
{
    if (IsEmpty()) //安全校验,是否为空表
    {
        return false;
    }
    if (i >= 0 && i <= last) {
        x = data[i - 1];
        for (int j = i; j <= last; j++)
        {
            data[j - 1] = data[j];
        }
        last--;
        return true;
    }
    else {
        return false;
    }
    
}

template<class T>
bool SeqList<T>::IsEmpty() const
{
    return last == -1 ? true : false;
}

template<class T>
bool SeqList<T>::IsFull() const
{
    return last + 1 == maxSize ? true : false;
}

template<class T>
void SeqList<T>::Input()
{
    cout << "开始建立顺序表,请输入表中元素的个数:";
    //利用死循环接收数据,如果输入格式正确跳出循环,错误继续接收输入值
    while (true) {
        cin >> last;
        last--;
        if (last<= maxSize-1 && last>=0) {
            break; //跳出循环
        }
        //提示:
        cout << "输入的元素个数不能超过存储上限:" << maxSize<< endl;
    }
    for (int i = 0; i <=last; i++)
    {
        cin >> data[i];
        if (i != last) {
            cout << "输入下一个数据:" << endl;
        }
        else {
            cout << "输入结束" << endl;
        }
    }
}

template<class T>
void SeqList<T>::Output()
{
    cout << "当前表中元素个数为:" << last + 1 << endl;
    for (int i = 0; i <= last; i++)
    {
        cout << "#" << i + 1 << ":" << data[i] << endl;
    }
}

template<class T>
 void SeqList<T>::Sort()  //利用冒泡算法进行排序
{
     for (int i = 0; i <= last; i++)
     {
         for (int j = 0; j <last; j++)
         {
             if (data[j] > data[j + 1]) {
                 this->Swap(j + 1, j + 2);
             }
         }
     }
}

 template<class T>
 void SeqList<T>::Add(T& x)
 {
     Insert(last+1, x);
 }

 template<class T>
  void SeqList<T>::Swap(int a,int b)  //交换第a个数字和第b个数字
 {
      T temp =data[a-1];
      data[a - 1] = data[b - 1];
      data[b - 1] = temp;     
 }

  template<class T>
   void SeqList<T>::Union(SeqList<T>& L2, SeqList<T>& res)
  {
       int leftLength = Length();
       int rightLength = L2.Length();
       res.Resize(leftLength + rightLength); //保证能存储的下
       for (int i = 0; i <= last; i++)
       {
           res.data[i]= data[i];
       }
       res.last = last;
       for (int i = 1; i <= L2.last+1; i++)
       {
           T temp;
           L2.GetData(i, temp);
           if (!res.Search(temp)) 
           {
               res.Add(temp);
           }
       }

  }

  template<class T>
   void SeqList<T>::Intersection(SeqList<T>& L2, SeqList<T>& res)  //交运算
  {
       if (Length() > L2.Length()) {
           res.Resize(Length());
       }
       else {
           res.Resize(L2.Length());
       }
       res.last = -1;
       for (int i = 1; i <= last+1; i++)
       {
           T temp;
           this->GetData(i, temp);
           if (L2.Search(temp)) {
               res.Add(temp);
           }
       }

  }

template<class T>
SeqList<T> SeqList<T>::operator=(SeqList<T>& L)
{
    maxSize = L.maxSize;
    delete[] data;
    data = new T[maxSize];
    last = L.last;
    for (int i = 1; i <= last + 1; i++)
    {
        T temp;
        L.GetData(i, temp);
        data[i - 1] = temp;
    }
}


template<class T>
ostream& operator<<(ostream& OutStream, SeqList<T>& OutList)
{
    OutStream << "数组内容 : " << endl;
    for (int i = 0; i < OutList.Length(); i++)
        OutStream << OutList.data[i] << "";
    OutStream << endl << "数组当前大小 : " << OutList.Length() << endl;
    return OutStream;

}
template<class T>
istream& operator>>(istream& in, SeqList<T>& inlist)
{

    cout << "开始建立顺序表,请输入表中元素的个数:";
    while (true) {
        in >> inlist.last;
        inlist.last--;
        if (inlist.last <= inlist.maxSize - 1 && inlist.last >= 0) {
            break; //跳出循环
        }
        //提示:
        cout << "输入的元素个数不能超过存储上限:" << inlist.maxSize << endl;
    }
    for (int i = 0; i <= inlist.last; i++)
    {
        in >> inlist.data[i];
        if (i != inlist.last) {
            cout << "输入下一个数据:" << endl;
        }
        else {
            cout << "输入结束" << endl;
        }
    }

    return in;


}

测试01

#include <iostream>
#include "LinearList.h"
using namespace std;

int main() {
	SeqList<int> seq01(3);   //构造函数测试
	cout << "顺序表是否为满:" << seq01.IsFull()<<endl;   //
	cout << "顺序表是否为空:" << seq01.IsEmpty() << endl;
	cout << "表的容量为:" << seq01.Size() << "表中存储的数据个数为" << seq01.Length() << endl;
	seq01.Input();  //输入函数测试
	cout <<"顺序表是否为满:"<< seq01.IsFull() << endl;
	cout <<"顺序表是否为空:"<<seq01.IsEmpty() << endl;
	seq01.Output();   //原始构造的列表输出

	cout << "移除第二个数字:"<<endl;
	int temp;   
    seq01.Remove(2, temp);  //移除函数测试
	cout << "表的容量为:" << seq01.Size() << "表中存储的数据个数为" << seq01.Length() << endl;
	seq01.Output(); //移除后列表输出

	cout << "在第一个数据后插入 5"<<endl;
	int m = 5;
	seq01.Insert(1, m);  //在第一个数据后插入5输出
	cout << "表的容量为:" << seq01.Size() << "表中存储的数据个数为" << seq01.Length() << endl;
	seq01.Output();


	cout <<"利用=运算符重载"<< endl;
	SeqList<int> seq02 = seq01;  //=运算符重载测试
	cout << "表的容量为:" << seq02.Size() << "表中存储的数据个数为" << seq02.Length() << endl;
	seq02.Output();


	cout << "使用resize进行扩容:" << endl;
	seq02.Resize(10);
	cout << "表的容量为:" << seq02.Size() << "表中存储的数据个数为" << seq02.Length() << endl;
	seq02.ResizeDouble();
	cout << "表的容量为:" << seq02.Size() << "表中存储的数据个数为" << seq02.Length() << endl;


	cout << "使用getdata获取指定位置的数字:" << endl;
	int temp01;
	if (seq02.GetData(2, temp01)) {
		cout << "第2个数字是:" << temp01 << endl;
	}

	cout << "使用setdata设置指定位置的数字:" << endl;
	int temp02=8;
	seq02.SetData(3, temp02);
	seq02.Output();

	cout << "使用复制构造函数" << endl;
	SeqList<int> seq03(seq02);
	seq03.Output();

}

在这里插入图片描述

测试02 排序

int main() {
	SeqList<int> seq04(6);
	seq04.Input();
	seq04.Output();
	seq04.Sort();
	seq04.Output();
}

在这里插入图片描述

测试03 模板类中使用友元函数重载<<和>>运算符

注意:写代码时遇到了报错,LNK2019 无法解析的外部符号 “class std::basic_ostream<char,struct std::char_traits > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits > &,class SeqList &)” (??6@YAAA
解决方法:声明的时候加上 **template < class T> **详见 参考资料2
在这里插入图片描述
测试代码:

int main() {
	SeqList<int>  seq08(10);
	cin >> seq08;
	cout << seq08;
}

运行结果:在这里插入图片描述

测试04 交和并

int main() {
	cout << "输入第一个顺序表" << endl;
	SeqList<int> seq05(3);
	seq05.Input();
	seq05.Output();
	cout << "输入第二个顺序表" << endl;
	SeqList<int> seq06(3);
	seq06.Input();
	seq06.Output();

	SeqList<int>  unionRes;
	seq05.Union(seq06, unionRes);
	cout << "union的结果是:" << endl;
	unionRes.Output();

	SeqList<int>  intersectionRes;
	seq05.Intersection(seq06, intersectionRes);
	cout << "Intersection的结果是:" << endl;
	intersectionRes.Output();
}

在这里插入图片描述

参考资料:

  1. 清华大学计算机系列教材 数据结构 殷人昆主编
  2. 在c++ 模板类外写 操作符重载函数,并且是模板类的友元函数
  3. C++运算符重载三种形式(成员函数,友元函数,普通函数)详解
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值