实验4.1 链表实现

实验4.1 链表实现

要求

  • 封装链表类,链表迭代器类
  • 不得使用与链表实现相关的STL
  • 链表类需提供操作
    1. 在指定位置插入元素
    2. 删除指定元素
    3. 搜索链表中是否有指定元素
    4. 原地逆置链表
    5. 输出链表

描述

第一行两个整数 N 和 Q。
第二行 N 个整数,作为节点的元素值,创建链表。
接下来 Q 行,执行各个操作,具体格式如下:

  • 插入操作 : 1 idx val,在链表的 idx 位置插入元素 val;
  • 删除操作 : 2 val,删除链表中的 val 元素。若链表中存在多个该元素,仅删除第一个。若该元素不存在,输出 -1
  • 逆置操作 : 3,原地逆置链表;
  • 查询操作 : 4 val,查询链表中的 val 元素,并输出其索引。若链表中存在多个该元素,仅输出第一个的索引。若不存在该元素,输出 -1
  • 输出操作 : 5,使用 链表迭代器 ,输出当前链表索引与元素的异或和: f ( chain ) = ∑ i = 0 n − 1 i ⊕ chain [ i ] , n = len(chain) f(\text{chain}) = \sum_{i=0}^{n-1}i\oplus \text{chain}[i], n=\text{len(chain)} f(chain)=i=0n1ichain[i],n=len(chain)

思路与探讨

线性表链式描述

笔记补充:详细写了线性表的链式描述

整体思路描述

  • 封装链表类,链表迭代器类;

  • 提供链表类相关操作函数:在指定位置插入元素,删除指定元素,搜索链表中是否有指定元素,原地逆置链表,输出链表;

  • 最后在主函数用枚举实现相关操作。

类chain函数的具体思路

构造函数

初始化建一个空表

复制构造函数

  • 若链表theList为空:直接将首节点置空
  • 若链表theList不为空
    • sourceNode依次指向theList的节点
    • 复制完成firstNode
    • 开一个targetNode作为*this的最后一个节点
    • 借助sourceNodetargetNode两个节点依次进行复制和后移

析构函数

重复删除链表的首节点

成员类iterator

  • 具备操作符:*、->、++、==、!
    • *操作符,获得迭代器所指的数据
    • ->操作符,获得迭代器所指数据的地址
    • 前++、后++:迭代器移到下(后)一个元素
    • ==、!=:判断是否相等
  • 为类chain增加:
    • begin():返回指向线性表首节点的指针
    • end():返回指向线性表尾节点的下一个位置

方法get

返回索引为theIndex的元素

  • 移动到所需要的节点
  • 找到后由节点指向元素并返回

方法indexOf

返回元素theElement首次出现时的索引 ,如果其不在表中,返回-1

  • currentNode从firstNode开始,并标记currentNode的索引
  • 循环查找元素
  • 确认是否找到

方法erase

情况(1):删除非空表的第0个元素(theIndex = 0)

  • 首节点的位置deleteNode;firstNode移到第1个节点
  • 释放deleteNode节点所占用的存储空间
  • listSize减1

情况(2):删除索引为theIndex元素步骤

  • 找到第theIndex-1和第theIndex个节点的位置pdeleteNode;
  • theIndex个节点的后继成为第theIndex-1个节点的后继
  • 释放deleteNode节点所占用的存储空间
  • listSize减1

方法insert

情况(1):在第theIndex = 0位置插入

  • 申请新节点
    • 新节点中元素:theElement
    • 新节点中指针:firstNode
  • 新节点成为首节点
  • listSize加1

情况(2):在第theIndex > 0位置插入

  • 找到第theIndex-1个元素的位置p

  • 申请新节点

    • 新节点中的元素:theElement
    • 新节点中的指针:p的后继(p->next)
  • 新节点成为p的后继

  • listSize加1

方法reverse

借助pastNode , currentNode , futureNode依次改变每个节点的指向,从而实现逆置。

浅录了个视频梳理了一下流程

方法sum

借助迭代器逐步遍历计算即可


若已看懂思路,试着自己写~


实现代码

#include<iostream>
using namespace std;

//结构chainNode
template<class T>  
struct chainNode
{
    //数据成员 
    T element;
    chainNode<T> *next; 
    //方法 
    chainNode() {}
    chainNode(const T &element)
    {
        this->element = element;
    }
    chainNode(const T &element,chainNode<T>*next)
    {
        this->element = element;
        this->next = next;
    }
};

//定义链表类
template<class T> 
class chain
{
    public:
    	//构造函数
        chain() 
		{
		    firstNode = NULL;
			listSize = 0;
		}
    
		//复制构造函数
        chain(const chain<T>& theList) 
        {
		    listSize = theList.listSize;
            //情况(1)链表theList为空
            if(listSize == 0)
			{ 
			    firstNode = NULL;
				return;
			}
            //情况(2)链表theList为非空 
            //要复制链表theList的节点
            chainNode<T>*sourceNode = theList.firstNode;
            //要复制链表theList的首元素
            firstNode = new chainNode<T>(sourceNode->element);
            //移向要复制的下一个节点
            sourceNode = sourceNode->next;
            //当前链表*this的最后一个节点 
            chainNode<T>*targetNode = firstNode;
            //复制剩余元素
            while(sourceNode != NULL)
            { 
                //复制
			    targetNode->next = new chainNode<T>(sourceNode->element);
                //后移
                targetNode = targetNode->next;
                sourceNode = sourceNode->next;
            }
            //链表结束 ,最后一个节点指向Null 
            targetNode->next = NULL;
        }
    
        //析构函数
        ~chain() 
        {
            while(firstNode)
            {//删除首节点 
                chainNode<T>*next = firstNode->next;//链式一节一节往后删 
                delete firstNode;
                firstNode = next;
            }
        }
    
		//链表的成员类iterator
        class iterator 
        {
            public:
            	//构造函数 
                iterator(chainNode<T>*theNode = NULL) 
                	{node = theNode;}
                //解引用操作符 
                T& operator*() const {return node->element;}
                T* operator->() const {return &node->element;}
                //迭代器加法操作 
                iterator& operator++() 
                	{node = node->next; return *this;}//前加 
                iterator operator++(int) 
					{iterator old = *this;node = node->next;return old;}//后加 
                //相等检验 
                bool operator != (const iterator right) const 
                	{return node != right.node;}
                bool operator == (const iterator right) const 
                	{return node == right.node;}
            protected:
                chainNode<T>*node;//指向表节点的指针
        };
    	//返回指向线性表首元素的指针
        iterator begin() {return iterator(firstNode);}
    	//返回指向线性表尾节点的下一个位置
        iterator end() {return iterator(NULL);} 

    	//返回索引为theIndex的元素 
        T& get(int theIndex) const 
        {
            //移向所需要的节点 
		    chainNode<T>*currentNode = firstNode;
            for(int i = 0;i<theIndex;i++) 
			    currentNode = currentNode->next;
            //找到后由节点指向元素并返回 
            return currentNode->element;
        }

    	//返回元素theElement首次出现时的索引 
        int indexOf(const T &theElement) const 
        {
            //从firstNode开始
		    chainNode<T>*currentNode = firstNode;
            //标记currentNode的索引
            int index = 0; 
            //查找元素
            while(currentNode != NULL && currentNode->element != theElement)
            {
                currentNode=currentNode->next;
                index++;
            }
            //确定是否找到所需的元素 
            if(currentNode==NULL) 
			    return -1;
			else 
                return index;
        }

    	//删除索引为theIndex的元素
        void erase(int theIndex) 
        {
            chainNode<T>*deleteNode;
            //情况(1):删除链表的首节点 
            if(theIndex == 0)
            {
			    deleteNode = firstNode;
                firstNode = firstNode->next;
			}
            //情况(2):删除索引为theIndex(≠0)元素
            else
            {
                //找到第theIndex-1和第theIndex个节点的位置p和deleteNode
                chainNode<T>*p = firstNode;
                for(int i = 0;i < theIndex - 1;i++)  
				    p = p->next;
                deleteNode = p->next;
                //第theIndex个节点的后继成为第theIndex-1个节点的后继
                p->next = p->next->next;
            }
            //listSize减1
            listSize--;
            //释放deleteNode节点所占用的存储空间
            delete deleteNode; 
        }

    	//在索引theIndex处插入元素theElement
        void insert(int theIndex,const T &theElement) 
        {
            //情况(1)在链表头插入 
		    if(theIndex == 0) 
			    firstNode = new chainNode<T>(theElement,firstNode);
            //情况(2)在第theIndex>0位置插入 
            else
			{
                //找到第theIndex-1个元素的位置p
			    chainNode<T>*p = firstNode;
                for(int i = 0;i < theIndex-1;i++) 
				    p = p->next;
                //申请新节点(其元素为theElement,指针为p的后继)
                //并让新节点成为p的后继
                p->next=new chainNode<T>(theElement,p->next);
            }
            //listSize加1
        	listSize++;
        }

    	//输出链表 
        void outPut(ostream &out) const 
        {
            //把链表放入输出流 
            for(chainNode<T>*currentNode = firstNode;
                currentNode != NULL;
                currentNode = currentNode->next)
                out<<currentNode->element<<" ";
        }

    	//逆置链表
        void reverse()  
        {
            if(firstNode == NULL||firstNode->next == NULL) return;//此时无需逆转 
            chainNode<T>*pastNode = firstNode;
            chainNode<T>*currentNode = pastNode->next;
            chainNode<T>*futureNode = currentNode->next;
            firstNode->next = NULL;
            while(futureNode != NULL)
            {
			    currentNode->next = pastNode;
                pastNode = currentNode;
                currentNode = futureNode;
                futureNode = futureNode->next;
            }
            currentNode->next = pastNode;
            firstNode = currentNode;
        }

    	//计算链表索引与元素的异或和
        int sum() 
        {
            int S = 0,index = 0;
            iterator beginning = begin();
            while(index < listSize)
            {
                S += index^(*beginning);
                beginning++;
                index++;
            }
            return S;
        }
    private:
        chainNode<T>*firstNode; //链表的头指针,即指向链表第一个节点的指针 
        int listSize; //链表的长度,即线性表元素的个数 
};

int main()
{
    int N,Q;
    cin>>N>>Q; //输入N和Q
    int *a=new int[N];
    for(int i=0;i<N;i++) cin>>a[i]; //输入节点元素值
    chain<int>Array; //创建链表
    for(int i=0;i<N;i++) Array.insert(i,a[i]); //插入各节点
    delete []a;
    for(int i=0;i<Q;i++) //执行Q次操作
    {
        int choice;
        cin>>choice; //输入操作序号
        int idx,val,index;
        switch(choice)
        {
        case 1:
            cin>>idx>>val; //输入1时,输入idx与val
            Array.insert(idx,val); //在idx处插入元素val
        break;
        case 2:
            cin>>val; //输入2时,输入val
            index=Array.indexOf(val); //查找val的位置
            if(index!=-1) Array.erase(index); //若存在,删除该元素
            else cout<<"-1"<<endl; //若不存在,输出-1
            break;
        case 3:
            Array.reverse(); //输入3时,原地逆置链表
            break;
        case 4:
            cin>>val; //输入4时,输入val
            cout<<Array.indexOf(val)<<endl; //查询val的位置
            break;
        case 5:
            cout<<Array.sum()<<endl; //输入5时,输出异或和
            break;
        default:
            break;
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

啦啦右一

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值