Bootstrap

【OJ01】顺序表-将顺序表中前 m 个元素和后 n 个元素进行互换(ADT+模板)

高亮:仅作个人复盘学习过程之用,写得很烂,专业术语也不会靠瞎扯,还有很多讲给自己的废话。目前是想先打好基础再搞花里胡哨的方法。

问题描述 :

在这里插入图片描述

输入说明 :

在这里插入图片描述

输出说明 :

在这里插入图片描述

输入范例 :

0
13 5 27 9 32 123 76 98 54 87
5

输出范例 :

13,5,27,9,32,123,76,98,54,87

123,76,98,54,87,13,5,27,9,32

解题思路:

刚开始学数据结构所以用最原始的方法,手写一个ADT,不用vector(其实是因为不会用)。因为输入有不同类型,所以用到了模板。

算法方面,本来一开始想的是把前面(a1,a2,…,am)依次插入到表尾,但是这样会多开辟m个空间。而且实际去做的时候想用Insrt这个基本操作,但是调用起来那个下标很麻烦,还是在Exchange这个函数里一步步实现比较清楚。

此题把插入者反一下就只需要一个辅助变量了。(感谢老师上课提点,我实在是有点笨)

此题解法:

在这里插入图片描述
在这里插入图片描述

贴代码:

先是顺序表(够用就行.ver)

#include<iostream>
using namespace std;

const int MAXSIZE=100;
//异常处理 不用看 没用到
#define OVERFLOW -2
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0

template<class ElemType>
class SqList
{
public://设成private还要写接口,好麻烦,只为了ac不用强求
    ElemType *elem;//存储基地址
    int length;//当前长度
    int ListSize;//允许的最大存储容量 以sizeof(ElemType)为单位
public:
    //初始化
    SqList(int maxsize=MAXSIZE);
    //销毁
    ~SqList();//这里把删表写成析构函数了,如果初始化和删除的时机想更灵活的话可以写成成员函数
};

template<class ElemType>
SqList<ElemType>::SqList(int maxsize)
{
    elem=new ElemType[MAXSIZE];
    //if(elem==NULL)//若分配内存不成功,说明数据溢出,没有地方可以存了
    //return OVERFLOW;构造函数没有返回值,所以不能这么干
    length=0;
    ListSize=maxsize;
}

template<class ElemType>
SqList<ElemType>::~SqList()
{
    delete []elem;//和new[]搭配使用 释放数组
    elem=NULL;
    length=0;
    ListSize=0;
}

这是关键的Exchange函数!

//本算法实现顺序表中前m个元素和后n个元素的互换,逆置位置m
template<class ElemType>
void Exchange( SqList<ElemType> &A, int m)
{
//局部变量的位置很重要啊,因为这个错了好几次
    int sub=0,cnt=0;//sub是数组a的第一个元素的下标,cnt是b的每个前插元素应该插入的地方(0,1,...,n-1)
    for(int i=m; i<A.length; ++i)//b数组有n个元素,所以前插n次
    {
        ElemType temp=A.elem[i];//保存b1.b2...bn 类型是ElemType
        for(int j=sub+m-1; j>=sub; --j) //从后往前(重要) 依次后移一位
        {
            A.elem[j+1]=A.elem[j];
        }
        ++sub;//sub不能放在上面的括号里面!否则移动次数就乱了!
        A.elem[cnt]=temp;
        cnt++;
    }
}

长~长的main函数

我写得有点麻烦,但代码不是写得短就是好的, 简单、好理解的才是好代码(对我这样的菜鸟友好)。

int main()
{
//par1 输入数据的类型
    int input_type;
    cin>>input_type;
    int cnt=0;
    
 //part2 根据不同输入类型进入不同分支
    switch(input_type)//0:int;1:double;2:char;3:string;其余值:输出err
    {
    case 0:
    {
        int n;//其实3个分支不同的只有这两句,类型改一下而已
        SqList<int> L;
        //复制复制复制。。。
        while(cin>>n)
        {
            L.elem[cnt]=n;
            ++cnt;
            ++L.length;
            if(cin.get()=='\n')//这个一定要放在存数据的后面,否则cin取到了87,cin.get()取到'\n'就会跳出while,最后一个数据就少存了
                break;
        }
        int m;
        cin>>m;
        //按格式先输出一遍交换前的数据
        for(int i=0; i<L.length-1; ++i)
            cout<<L.elem[i]<<",";
        cout<<L.elem[L.length-1]<<endl;
        cout<<endl;
        Exchange(L,m);
        for(int i=0; i<L.length-1; ++i)
            cout<<L.elem[i]<<",";
        cout<<L.elem[L.length-1]<<endl;
        break;
    }
    case 1:
    {
        double n;
         SqList<double> L;
        while(cin>>n)
        {
            L.elem[cnt]=n;
            ++cnt;
            ++L.length;
            if(cin.get()=='\n')
                break;
        }
        int m;
        cin>>m;
        for(int i=0; i<L.length-1; ++i)
            cout<<L.elem[i]<<",";
        cout<<L.elem[L.length-1]<<endl;
        cout<<endl;
        Exchange(L,m);
        for(int i=0; i<L.length-1; ++i)
            cout<<L.elem[i]<<",";
        cout<<L.elem[L.length-1]<<endl;
        break;
    }
    case 2:
    {
        char n;
         SqList<char> L;
        while(cin>>n)
        {
            L.elem[cnt]=n;
            ++cnt;
            ++L.length;
            if(cin.get()=='\n')               
                break;
        }
        int m;
        cin>>m;
        for(int i=0; i<L.length-1; ++i)
            cout<<L.elem[i]<<",";
        cout<<L.elem[L.length-1]<<endl;
        cout<<endl;
        Exchange(L,m);
        for(int i=0; i<L.length-1; ++i)
            cout<<L.elem[i]<<",";
        cout<<L.elem[L.length-1]<<endl;
        break;
    }
    case 3:
    {
        string n;
         SqList<string> L;
        while(cin>>n)
        {
            L.elem[cnt]=n;
            ++cnt;
            ++L.length;
            if(cin.get()=='\n')
                break;
        }
        int m;
        cin>>m;
        for(int i=0; i<L.length-1; ++i)
            cout<<L.elem[i]<<",";
        cout<<L.elem[L.length-1]<<endl;
        cout<<endl;
        Exchange(L,m);
        for(int i=0; i<L.length-1; ++i)
            cout<<L.elem[i]<<",";
        cout<<L.elem[L.length-1]<<endl;
        break;
    }
    default://为了在输入不正确时退出,只能把所有输出代码复制一遍到每个case。。。
        cout<<"err"<<endl;
        break;
    }
    return 0;
}

反思

1、这种算法虽然好想,但是两层for循环时间复杂度O(m*n),平方级的时间复杂度在数据量很大时很容易超时。还有种三次逆置的方法更好。
2、用vector会方便很多。
3、main函数部分确实很啰嗦,重复部分搞个函数。
3、不是我不想一题多解,是ddl将近。。。有空再用别的方法实现一遍。

;