4.单链表ADT模板简单应用算法设计:单链表中前 m 个元素和后 n 个元素的互换

2023-11-07

问题描述 :

目的:使用C++模板设计单链表的抽象数据类型(ADT)。并在此基础上,使用单链表ADT的基本操作,设计并实现单链表的简单算法设计。

内容:(1)请使用模板设计单链表的抽象数据类型。(由于该环境目前仅支持单文件的编译,故将所有内容都集中在一个源文件内。在实际的设计中,推荐将抽象类及对应的派生类分别放在单独的头文件中。参考网盘中的ADT原型文件。)

(2)ADT的简单应用:使用该ADT设计并实现单链表应用场合的一些简单算法设计。

应用1:假设有一个带头结点的单链表A,现要求设计一个算法,实现单链表的就地逆置,即利用原表的存储空间实现表中前m 个元素和后n 个元素的互换。

参考函数原型:

template<class ElemType>

void Exchange_L( LinkList<ElemType> &L, int m );

单链表ADT原型如下:

/* 单链表的结点定义 */
template<class ElemType>
struct LinkNode
{
    ElemType data;
    LinkNode<ElemType> *next;
    LinkNode(LinkNode<ElemType> *ptr = NULL){next = ptr;}
    LinkNode(const ElemType &item, LinkNode<ElemType> *ptr = NULL)   
    //函数参数表中的形参允许有默认值,但是带默认值的参数需要放后面
    {
        next = ptr;
        data = item;
    }
};

//带头结点的单链表
template<class ElemType>
class LinkList:public link<ElemType>
{
   private:
      LinkNode<ElemType> *head;   // 头指针
      LinkNode<ElemType> *tail;   // 尾指针

   public:
      //无参数的构造函数
      LinkList(){head = new LinkNode<ElemType>; tail =head;}
      //带参数的构造函数
      LinkList(const ElemType &item){head = new LinkNode<ElemType>(item); tail = head;}
      //拷贝构造函数
      LinkList(LinkList<ElemType> &List);
      //析构函数
      ~LinkList(){ListDestroy();}
      //重载函数:赋值
      LinkList<ElemType>& operator=(LinkList<ElemType> &List);
      //销毁链表
      void ListDestroy();
      //清空链表
      void ListClear();
      //返回链表的长度
      int ListLength() const;
      //判断链表是否为空表
      bool ListEmpty() const;
      //在首结点之前插入一个结点
      bool InsFirst( ElemType &e );
      //在尾结点之前插入一个结点
      bool InsTail( ElemType &e );

      //获取链表头指针
      LinkNode<ElemType>* GetHead() const{ return head;}
      //获取链表尾指针
      LinkNode<ElemType>* GetTail() const{ return tail;}

      //设置链表头指针
      void SetHead(LinkNode<ElemType> *p){ head = p;}      
      //设置链表尾指针
      void SetTail(LinkNode<ElemType> *p){ tail = p;}      

      //用e返回链表的第i个元素
      ElemType GetElem(int pos);
      //在链表的第pos个位置之前插入e元素
      bool ListInsert(int pos,ElemType e);
      //删除链表的首结点
      //bool DelFirst( ElemType &e);
      //表头插入法动态生成链表
      void CreateList_Head(vector<ElemType> &A);     
      //表尾插入法动态生成链表
      void CreateList_Tail(vector<ElemType> &A);    
      //删除链表的第pos个位置的元素
      ElemType ListDelete(int pos);
      //compare函数,用来判断a和b是否相等
      //bool compare(ElemType a, ElemType *b);
      //按指定条件查找,返回指向第一个符合条件(=e)的元素的指针
      bool LocateElem(const ElemType &e, LinkNode<ElemType> * &pos);
      //返回链表给定数据元素的前驱数据元素的值
      //bool PriorElem(ElemType cur_e, ElemType &pri_e);
      //返回链表给定数据元素的后继数据元素的值
      bool NextElem(LinkNode<ElemType> *p, ElemType &e);
      //遍历链表
      bool ListTraverse() const;
};

输入说明 :

第一行:顺序表A的数据元素的数据类型标记(0:int,1:double,2:char,3:string)

第二行:待逆置单链表的数据元素(数据元素之间以空格分隔)

第三行:逆置位置m

输出说明 :

如第一行输入值为0、1、2、3之外的值,直接输出“err”

否则:

第一行:待逆置单链表的遍历结果(数据元素之间以"->"分隔)

空行

第三行:逆置后单链表的遍历结果(数据元素之间以"->"分隔)

这是一条分割线 


题解

对于其中的关键exchange函数的解析:

可以参考某网友的图解

 

法一:在创建单链表时,cin>>elem一个一个输入节点

完整AC代码:

#include<iostream>
using namespace std;

template<class T>
 struct LNode{
	T data;
	LNode<T>* next=NULL;
};

//遍历输出 
template <class T>
void traverse(LNode<T>& L,int length){
	LNode<T>* p=&L;//p初始化指向头节点
	for(int i=1;i<length;++i)
	{
		p=p->next;
		cout<<p->data<<"->";
	}
	cout<<p->next->data;
}
//将前m个节点与后n个节点互换 
template <class T>
void exchange(LNode<T>& L,int  m,int length){
	LNode<T>* rear;//尾指针 
	LNode<T>* p=&L;//p初始化指向头节点 
	LNode<T>* pm;
	
	for(int i=1;i<=length;i++)
	{
		p=p->next;
		if(i==m)	pm=p;//pm指向第m个节点 
	}
	rear=p;
	
	rear->next=L.next;
	L.next=pm->next;
	rear=pm;
}
//用后插法创建单链表 
template <class T>
void create(LNode<T>& L,int & length){

	LNode<T>* rear=&L;//尾指针 
	LNode<T>* p;//p用来指向每一个新输入的节点 
	T elem;
	while(cin>>elem)
	{
		length++;
		p=new LNode<T>;
		p->data=elem;
		rear->next=p;
		rear=p;
		if(cin.get()=='\n')	break;
		//cin会跳过空格和tab,cin.get()不会跳过空格,tab,回车 
	}
}

int main(){
	int kind=0;
	cin>>kind;
	if(kind==0)
	{
		LNode<int> L;
		int len=0;
		create(L,len);
		int m=0;
		cin>>m;
		traverse(L,len);
		cout<<endl<<endl;
		exchange(L,m,len);
		traverse(L,len);
	}
	else if(kind==1)
	{
		LNode<double> L;
		int len=0;
		create(L,len);
		int m=0;
		cin>>m;
		traverse(L,len);
		cout<<endl<<endl;
		exchange(L,m,len);
		traverse(L,len);
	}
	else if(kind==2)
	{
		LNode<char> L;
		int len=0;
		create(L,len);
		int m=0;
		cin>>m;
		traverse(L,len);
		cout<<endl<<endl;
		exchange(L,m,len);
		traverse(L,len);
	}
	else if(kind==3)
	{
		LNode<string> L;
		int len=0;
		create(L,len);
		int m=0;
		cin>>m;
		traverse(L,len);
		cout<<endl<<endl;
		exchange(L,m,len);
		traverse(L,len);
	}
	else
	{
		cout<<"err";
	}
	
	
	
	return 0;
}

 其中中的create函数创建单链表的方法借鉴了,DHU另一位朋友的写法

本菜鸟学到了用cin>>elem,和用cin.get()=='\n',来进行输入。cin,get()不会跳过空格,tab,以及换行符。

另外在写各个函数时,我用LNode<T>* L来作形参老是出问题,暂时我不清楚问题出在哪儿了,所以先略过。

法二:用getline(cin,str)整行输入,再用stringstream 类将str转换为单个节点存入链表。

只是在

template <class T>
void create(LNode<T>& L,int & length,stringstream &stream){

	LNode<T>* rear=&L;//尾指针 
	LNode<T>* p;//p用来指向每一个新输入的节点 
	T elem;
	while(stream>>elem)
	{
		length++;
		p=new LNode<T>;
		p->data=elem;
		rear->next=p;
		rear=p;
	}
}

 和主函数main()中有略微差别

int kind=0;
	cin>>kind;
	cin.get();//跳过换行符 
	string str;
	getline(cin,str);//结束符'\n'不会放入缓存区,会将读入的'\n'直接去除 
	stringstream stream;
	stream<<str;
	if(kind==0)
	{
		LNode<int> L;
		int len=0;
		create(L,len,stream);
		int m=0;
		cin>>m;
		traverse(L,len);
		cout<<endl<<endl;
		exchange(L,m,len);
		traverse(L,len);
	}

完整AC代码: 

#include<bits/stdc++.h>
using namespace std;

template<class T>
 struct LNode{
	T data;
	LNode<T>* next=NULL;
};

//遍历输出 
template <class T>
void traverse(LNode<T>& L,int length){
	LNode<T>* p=&L;//p初始化指向头节点
	for(int i=1;i<length;++i)
	{
		p=p->next;
		cout<<p->data<<"->";
	}
	cout<<p->next->data;
}
//将前m个节点与后n个节点互换 
template <class T>
void exchange(LNode<T>& L,int  m,int length){
	LNode<T>* rear;//尾指针 
	LNode<T>* p=&L;//p初始化指向头节点 
	LNode<T>* pm;
	
	for(int i=1;i<=length;i++)
	{
		p=p->next;
		if(i==m)	pm=p;//pm指向第m个节点 
	}
	rear=p;
	
	rear->next=L.next;
	L.next=pm->next;
	rear=pm;
}
//用后插法创建单链表 
template <class T>
void create(LNode<T>& L,int & length,stringstream &stream){

	LNode<T>* rear=&L;//尾指针 
	LNode<T>* p;//p用来指向每一个新输入的节点 
	T elem;
	while(stream>>elem)
	{
		length++;
		p=new LNode<T>;
		p->data=elem;
		rear->next=p;
		rear=p;
	}
}

int main(){
	int kind=0;
	cin>>kind;
	cin.get();//跳过换行符 
	string str;
	getline(cin,str);//结束符'\n'不会放入缓存区,会将读入的'\n'直接去除 
	stringstream stream;
	stream<<str;
	if(kind==0)
	{
		LNode<int> L;
		int len=0;
		create(L,len,stream);
		int m=0;
		cin>>m;
		traverse(L,len);
		cout<<endl<<endl;
		exchange(L,m,len);
		traverse(L,len);
	}
	else if(kind==1)
	{
		LNode<double> L;
		int len=0;
		create(L,len,stream);
		int m=0;
		cin>>m;
		traverse(L,len);
		cout<<endl<<endl;
		exchange(L,m,len);
		traverse(L,len);
	}
	else if(kind==2)
	{
		LNode<char> L;
		int len=0;
		create(L,len,stream);
		int m=0;
		cin>>m;
		traverse(L,len);
		cout<<endl<<endl;
		exchange(L,m,len);
		traverse(L,len);
	}
	else if(kind==3)
	{
		LNode<string> L;
		int len=0;
		create(L,len,stream);
		int m=0;
		cin>>m;
		traverse(L,len);
		cout<<endl<<endl;
		exchange(L,m,len);
		traverse(L,len);
	}
	else
	{
		cout<<"err";
	}
	
	
	
	return 0;
}

本菜鸟学到了:

1.getline(cin,str),可以输入整行,对于行末结束符'\n'不会放入缓存区,直接舍弃

2.stringstream  stream:常用于string字符串数据类型转换,详细信息请参考关于stringstream的使用

(有问题欢迎在评论区讨论)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

4.单链表ADT模板简单应用算法设计:单链表中前 m 个元素和后 n 个元素的互换 的相关文章

随机推荐

  • ROS机器人语音模块

    ROS机器人语音模块 文章目录 ROS机器人语音模块 零 乘骐骥以驰骋兮 来吾道夫先路 壹 路漫漫其修远兮 吾将上下而求索 贰 苟余情其信姱以练要兮 长顑颔亦何伤 叁 不吾知其亦已兮 苟余情其信芳 肆 虽体解吾犹未变兮 岂余心之可惩 末 亦
  • 【仿真】Carla介绍与使用 [1] (附代码手把手讲解)

    0 参考与前言 主要介绍无人驾驶的仿真环境CARLA 开源社区维护 以下为相关参考链接 Carla官方文档 建议后续找的时候 先按好版本号 有些功能 api 是新版本里有的 Carla官方github Youtube Python Wind
  • vue css >>> , /deep/ 深度选择器

    vue引用了第三方组件 有时候我们需要改写第三方组件的样式 而又不想去除scoped属性造成组件之间的样式污染 此时只能通过 gt gt gt 穿透scoped 有些Sass 之类的预处理器无法正确解析 gt gt gt 这时可以使用 de
  • stm32 利用链表和定时器动态实现led等器件周期性控制

    stm32 esp8266 ota系列文章 stm32 esp8266 ota 快速搭建web服务器之docker安装openresty stm32 esp8266 ota升级 tcp模拟http stm32 esp8266 ota升级 h
  • 初探 ModBus4j -简单使用指南

    目录 前言 开发环境 工具准备 具体实现 下载Modbus4j 解决空指针异常 解决数组越界 测试 测试环境准备 正式测试 前言 之前提到过 由于项目需求 需要封装 ModBus协议 ModBus协议较早 网上开源开源库也不少 可参见 Mo
  • STM32驱动8266-----8266AP模式

    找了很久 一直没有找到驱动的程序 查一些资料 字写了一个简单程序 记录分享一下 void esp8266 inittcp void printf AT CIPMODE 2 r n 设置AP模式 delay ms 10000 延时函数 pri
  • vue3.0教程——搭建Vue脚手架【简化版】

    目录 哈喽 大家好丫 你们的小郭子又来啦 一 环境要求 1 node安装 前端开发环境 2 vue cli脚手架安装 二 安装依赖 1 使用命令行安装以下依赖 2 通过 vue ui 命令以图形化界面来管理项目依赖 3 导入你刚刚项目的地址
  • 装系统使用默认administrator用户

    在设置键盘布局界面按下Ctrl Shift F4重启 进入系统后 见到一个 系统准备工具 3 14 开始 运行 输入 XCOPY windir System32 svchost exe windir System32 oobe audit
  • MyBatis框架( 项目构建笔记 )

    MyBatis框架 项目构建笔记 一 框架 二 获取参数 三 查询 四 模糊查询 批量删除 五 resultMap和映射关系 五 动态SQL 基本功能实现的项目结构 将SqlSessionFactory 使用工具类进行封装 映射文件的名称要
  • 牛客 AB28 快速幂 JAVA

    描述 请你计算 ab mod p 的值 一共有 q 次询问 输入描述 第一行输入一个正整数 q 代表询问次数 接下来每行输入三个正整数 a b p 代表一次询问 数据范围 1 1051 q 105 1 1071 a b p 107 输出描述
  • BatchNormalization、LayerNormalization、InstanceNorm、GroupNorm、SwitchableNorm总结

    本篇博客总结几种归一化办法 并给出相应计算公式和代码 1 综述 1 1 论文链接 1 Batch Normalization https arxiv org pdf 1502 03167 pdf 2 Layer Normalizaiton
  • 解决git分支切换时遇到的问题

    Please commit your changes or stash them before you switch branches问题的解决 在项目开发的过程中 有时候会遇到一个分支上的BUG还没解决 另一个分支上的BUG又急需解决 这
  • docker 安装mysql总是报错

    完全卸载mysql 把所有的mysql 相关的文件全部删除 find name mysql 查到文件全部删除
  • OpenGL 入门 19:内建变量、接口块、Uniform缓冲

    一 内建变量 查询所有的内建变量的话 请查看OpenGL的wiki 顶点着色器 Input 变量名称 变量类型 变量语义 作用 gl VertexID int 索引 当使用glDrawElements 存储的是正在绘制顶点的当前索引 当使用
  • linux下多线程的创建和结构体传参

    下面总结一下linux下多线程的创建和传参 这里的传的参数是结构体的地址 然后在子线程中输出所传结构体对象的值 实现过程非常简单 其中pthread create 创建子线程 pthread join 是等待阻塞子线程结束 pthread
  • 在Python学习中遇到的一个疑问(可能已解决)

    文章目录 问题 分析 问题 从网上扒拉出来一段代码 是关于函数重写的 输出结果比较正常 但某些函数不太懂 python usr bin python3 class Vector def init self a b self a a self
  • Vue组件之间的通信方式

    六种方式 1 props emit 适用于 父子组件通信 略 2 ref 与 parents children 适用于父子组件通信 不好维护 不推荐使用 3 EventBus 适用于 父子 隔代 兄弟组件通信 这种方法通过一个空的 Vue
  • 每日sql-复购率问题count+case+timediff类函数

    记录一下案例 下次直接拿起来用
  • Python异常捕获及自定义异常类

    Python异常捕获及自定义异常类 一 什么是异常 异常是一个与业务逻辑无关的BUG 一个潜在错误或者网络错误事件等 如 尚未实现的函数 缩进错误 Python语法错误等 该事件可能会在程序执行过程中发生 影响程序的正常执行 在Python
  • 4.单链表ADT模板简单应用算法设计:单链表中前 m 个元素和后 n 个元素的互换

    问题描述 目的 使用C 模板设计单链表的抽象数据类型 ADT 并在此基础上 使用单链表ADT的基本操作 设计并实现单链表的简单算法设计 内容 1 请使用模板设计单链表的抽象数据类型 由于该环境目前仅支持单文件的编译 故将所有内容都集中在一个