TypeScript算法专题 - blog4 - 单链表节点的两-两翻转(两两一组逆序)

简介: TypeScript算法专题 - blog4 - 单链表节点的两-两翻转(两两一组逆序)

TypeScript数据结构与算法专题 -
[单链表4] 单链表节点的`两-两`反转的实现

1 交换数据法实现链表结点的两两反转

这种方法只需要将相邻的链表的数据域所存储的内容以每两个一组的形式进行互换,实际上并不需要改变改变链表中任何结点的连接关系。过程可以用下图来表示:

这里我们采用了双指针,前一个指针和后一个指针分别指向一组中的前后两个结点。从一组到下一组的过程就是一组中的两个指针同时每向后移动两个结点的过程。

其实现代码如下:

swapDataBy2():void{
    /**采用交换数据法以每2个结点一组翻转相邻元素 */
    let pointer_pre: Lnode = this.head;          // 从指向第1个结点开始
    let pointer_next: Lnode = this.head.next;    // 从指向第2个结点开始
    if(this.length %2 ==0){
        // 恰好偶数个结点
        while(pointer_next.next!=null){
            // 交换数据
            let data = pointer_pre.data;            // 暂存前一个结点的数据
            pointer_pre.data = pointer_next.data;   // 前一个结点接收后一个结点的数据
            pointer_next.data = data;               // 后一个结点接收(暂存的)前一个结点的数据
            // 移动指针
            pointer_pre = pointer_pre.next.next;
            pointer_next = pointer_next.next.next;
        }
    }else{
        // 奇数个结点
        while(pointer_next.next.next!=null){
            // 交换数据
            let data = pointer_pre.data;
            pointer_pre.data = pointer_next.data;
            pointer_next.data = data;
            // 移动指针
            pointer_pre = pointer_pre.next.next;
            pointer_next = pointer_next.next.next;
        }
    }
    // 最后一组
    let data = pointer_pre.data;
    pointer_pre.data = pointer_next.data;
    pointer_next.data = data;
}

代码测试

现在我们将该方法添加到之前写的链表类中,(之前的详细代码见上一篇博客《链表的合并以及对TypeScript链表实现中的一些问题总结与改进》中的完整代码部分)分别测试一下对含有奇数和偶数个结点的链表实现两个一组翻转的效果,为了方便查看,我们依然是转化为结点数组后输出。

【text1】奇数个结点分组翻转

let list = new LinkList([1,2,3,4,5,6,7,8,9]);
list.swapDataBy2()
console.log(list.toArray());

Out[]:

[
  Lnode { empty: false, data: 2, next: null },
  Lnode { empty: false, data: 1, next: null },
  Lnode { empty: false, data: 4, next: null },
  Lnode { empty: false, data: 3, next: null },
  Lnode { empty: false, data: 6, next: null },
  Lnode { empty: false, data: 5, next: null },
  Lnode { empty: false, data: 8, next: null },
  Lnode { empty: false, data: 7, next: null },
  Lnode { empty: false, data: 9, next: null } 
]

【text】偶数个结点分组翻转

let list = new LinkList([1,2,3,4,5,6,7,8,9,10]);
list.swapDataBy2()
console.log(list.toArray());

Out[]:

[
  Lnode { empty: false, data: 2, next: null }, 
  Lnode { empty: false, data: 1, next: null }, 
  Lnode { empty: false, data: 4, next: null }, 
  Lnode { empty: false, data: 3, next: null }, 
  Lnode { empty: false, data: 6, next: null }, 
  Lnode { empty: false, data: 5, next: null }, 
  Lnode { empty: false, data: 8, next: null }, 
  Lnode { empty: false, data: 7, next: null }, 
  Lnode { empty: false, data: 10, next: null },
  Lnode { empty: false, data: 9, next: null }  
]

2 改变结点引用关系实现链表结点的两两反转

接下来我们采用另一种方法来完成两两翻转的目的。实际上,在1.1节中的方法,我们的各结点之间的链接关系始终是保持不变的,并没有真正调整过结点的连接方式,改变的只是各个结点的数据。而接下来我们这一种方式才是真正从结点的关系上实现反转。这次,我们打算使用一个指针,从原链表的头节点开始,依次以2个结点向链表的尾元结点方向移动。

我们期待的过程大概是这样子的

在这种实现中有一个十分需要注意的地方。

假设变量p是对某一个结点对象的引用(指向某个结点对象),如果你在代码中将引用另外一个对象的变量赋值给变量p并不会对变量p所引用的对象做任何改变,而只会进行引用的传递,即让p引用到另外一个变量索引用的相同一个对象。

如果p是一个结点对象的引用,你能通过p修改的只不过是这个对象所拥有的一些属性,如p.next,而绝不能觊觎通过对p赋值使得其它引用到这个对象的引用发生改变。

这意味着,你要通过引用来更改结点需要引用到被更改结点的前驱结点。因此在实现时要注意区分是通过引用修改对象还是直接修改对象本身。

基于以上原因,我们实际上不能直接由上图的过程完成相邻元素的翻转。为了方便起见,我这里采用了一个我称之为虚拟挂载点的空结点,它指向原链表头节点,相当于头节点指针。而接下来在实行翻转时,我们只需要一个指针,初始指向虚拟挂载点,之后每次后指两个结点。

代码实现如下:

reverseBy2():void{
    /**
     * 将链表中的结点每2个一组进行翻转
     */
    // 只组要考虑结点个数多于或等于2个的情况
    if(!(this.head==null || this.head.next==null)){ 
        let pre = new Lnode();      // 虚拟挂载点
        pre.next = this.head;       // 虚拟挂载点后继指向从点结点开始的所有结点
        let pointer:Lnode = pre;    // 指针初始指向虚拟挂载点
        while(pointer.next!=null && pointer.next.next!==null){
            let node:Lnode = pointer.next;
            pointer.next = pointer.next.next;
            node.next = pointer.next.next;      
            pointer.next.next = node;
            pointer = pointer.next.next;
        }
        this.head = pre.next;       // 从虚拟挂载点卸载
    }
}

代码测试

let list = new LinkList([1,2,3,4,5,6,7,8,9,10]);
list.reverseBy2()
console.log(list.toArray());

Out[]:

[
  Lnode { empty: false, data: 2, next: null }, 
  Lnode { empty: false, data: 1, next: null }, 
  Lnode { empty: false, data: 4, next: null }, 
  Lnode { empty: false, data: 3, next: null }, 
  Lnode { empty: false, data: 6, next: null }, 
  Lnode { empty: false, data: 5, next: null }, 
  Lnode { empty: false, data: 8, next: null }, 
  Lnode { empty: false, data: 7, next: null }, 
  Lnode { empty: false, data: 10, next: null },
  Lnode { empty: false, data: 9, next: null }  
]

可以看到,顺利达到了两个一组进行翻转的目的。

喜欢的话记得来个一赞三连鼓励哦(^U^)ノ~YO感激不尽

目录
相关文章
|
13天前
|
机器学习/深度学习 运维 算法
基于粒子群优化算法的配电网光伏储能双层优化配置模型[IEEE33节点](选址定容)(Matlab代码实现)
基于粒子群优化算法的配电网光伏储能双层优化配置模型[IEEE33节点](选址定容)(Matlab代码实现)
|
29天前
|
机器学习/深度学习 并行计算 算法
基于改进的粒子群算法PSO求解电容器布局优化问题HV配电中的功率损耗和成本 IEEE34节点(Matlab代码实现)
基于改进的粒子群算法PSO求解电容器布局优化问题HV配电中的功率损耗和成本 IEEE34节点(Matlab代码实现)
|
13天前
|
并行计算 算法 安全
【ADMM、碳排放】基于分布式ADMM算法的考虑碳排放交易的电力系统优化调度研究【IEEE6节点、IEEE30节点、IEEE118节点】(Matlab代码实现)
【ADMM、碳排放】基于分布式ADMM算法的考虑碳排放交易的电力系统优化调度研究【IEEE6节点、IEEE30节点、IEEE118节点】(Matlab代码实现)
|
2月前
|
机器学习/深度学习 算法 数据挖掘
基于自适应遗传算法风光场景生成的电动汽车并网优化调度【IEEE33节点】(Matlab代码实现)
基于自适应遗传算法风光场景生成的电动汽车并网优化调度【IEEE33节点】(Matlab代码实现)
|
5月前
|
SQL 分布式计算 DataWorks
使用DataWorks PyODPS节点调用XGBoost算法
本文介绍如何在DataWorks中通过PyODPS3节点调用XGBoost算法完成模型训练与测试,并实现周期离线调度。主要内容包括:1) 使用ODPS SQL构建数据集;2) 创建PyODPS3节点进行数据处理与模型训练;3) 构建支持XGBoost的自定义镜像;4) 测试运行并选择对应镜像。适用于需要集成机器学习算法到大数据工作流的用户。
184 24
|
5月前
|
传感器 算法 数据安全/隐私保护
基于GA遗传优化的三维空间WSN网络最优节点部署算法matlab仿真
本程序基于遗传算法(GA)优化三维空间无线传感网络(WSN)的节点部署,通过MATLAB2022A实现仿真。算法旨在以最少的节点实现最大覆盖度,综合考虑空间覆盖、连通性、能耗管理及成本控制等关键问题。核心思想包括染色体编码节点位置、适应度函数评估性能,并采用网格填充法近似计算覆盖率。该方法可显著提升WSN在三维空间中的部署效率与经济性,为实际应用提供有力支持。
|
8月前
|
存储 算法 Java
算法系列之递归反转单链表
递归反转链表的基本思路是将当前节点的next指针指向前一个节点,然后递归地对下一个节点进行同样的操作。递归的核心思想是将问题分解为更小的子问题,直到达到基本情况(通常是链表末尾)。
193 5
算法系列之递归反转单链表
|
7天前
|
传感器 机器学习/深度学习 算法
【使用 DSP 滤波器加速速度和位移】使用信号处理算法过滤加速度数据并将其转换为速度和位移研究(Matlab代码实现)
【使用 DSP 滤波器加速速度和位移】使用信号处理算法过滤加速度数据并将其转换为速度和位移研究(Matlab代码实现)
|
9天前
|
传感器 算法 数据挖掘
基于协方差交叉(CI)的多传感器融合算法matlab仿真,对比单传感器和SCC融合
基于协方差交叉(CI)的多传感器融合算法,通过MATLAB仿真对比单传感器、SCC与CI融合在位置/速度估计误差(RMSE)及等概率椭圆上的性能。采用MATLAB2022A实现,结果表明CI融合在未知相关性下仍具鲁棒性,有效降低估计误差。
|
10天前
|
负载均衡 算法 调度
基于遗传算法的新的异构分布式系统任务调度算法研究(Matlab代码实现)
基于遗传算法的新的异构分布式系统任务调度算法研究(Matlab代码实现)
82 11

热门文章

最新文章