2. 线性表 - 单链表的反转,相交算法

2. 线性表 - 单链表的反转,相交算法

2.1 单链表的反转

  • 反转链表,就是实现链表整体“反过来”,将头变成尾、尾变成头

2.1.1 迭代反转链表

  • 迭代反转法的实现思想是从当前链表的首元节点开始,一直遍历至链表的最后一个节点,这期间会逐个改变所遍历到的节点的指针域,另其指向前一个节点
  • 具体思路流程图和实现代码如下:
    在这里插入图片描述
// 迭代反转法
link* Iteration_reverse(link* head) {
    if (head == NULL || head->next == NULL) {
        return head;
    }
    link* beg = NULL;
    link* mid = head;
    link* end = head->next;
    while ( end ) {    // end为NULL时结束
        mid->next = beg;
        beg = mid;
        mid = end;
        end = end->next;
    }
    mid->next = beg;  // 结束时,需要将最后一个和前面连接上
    return mid;
}

2.1.2 递归反转链表

  • 递归反转法的实现思想是从链表的尾节点开始,依次向前遍历,遍历过程依次改变各节点的指向,即另其指向前一个节点。
  • 具体思路流程图和实现代码如下:
    在这里插入图片描述
// 递归反转法
link* Recursive_reverse(link* head) {
    if (head == NULL || head->next == NULL) {   
        return head;   // 递归的出口,也是原始链表是否需要反转的初始判断
    }
    link* new_head = Recursive_reverse(head->next);
    // 递归到new_head指向最后一个结点, 此时head指向的倒数第二个
    head->next->next = head;   // 递归返回中,head逐渐向前移动
    head->next = NULL;
    return new_head;
}

2.1.3 头插法反转链表

  • 头插法 是指在原有链表的基础上,依次将位于链表头部的节点摘下,然后采用从头部插入的方式生成一个新链表
  • 具体思路流程图和实现代码如下:
    在这里插入图片描述
//头插法反转链表
link* head_reverse(link* head) {
    if (head == NULL || head->next == NULL) {
        return head; 
    }
    link* new_head = NULL;
    link* temp = NULL; // temp是一个不可缺少的接力棒
    while (head) {
        temp = head; // 摘除需要反转的链表的结点
        head = head->next; // head向后移动
        temp->next = new_head; // 将摘下的结点指向新的结点
        new_head = temp;  // new_head向后指向新的头结点
    }
    return new_head;
}

2.1.4 就地逆置法反转链表

  • 就地逆置法和头插法的实现思想类似,唯一的区别在于,头插法是通过建立一个新链表实现的,而就地逆置法则是直接对原链表做修改,从而实现将原链表反转
  • 具体思路流程图和实现代码如下:
    在这里插入图片描述
// 就地逆置法
link* local_reverse(link* head) {
    if (head == NULL || head->next == NULL) {
        return head;
    }
    link* beg = head ;
    link* end = head->next ;
    while (end) {
        beg->next = end->next; //将 end 从链表中摘除
        end->next = head;  //将 end 移动至链表头
        head = end;  // head 接替成为头
        end = beg->next; //end 回到beg后面去
    }
    return head;
}

2.2 单链表的相交

  • 单链表相交,则意味着它们有公共的节点,公共节点的数量可以是 1 个或者多个。根据单链表的特性:每个节点有且仅有 1 个指针域,因此相交示意图如下:
    在这里插入图片描述
  • 思路一 :分别遍历链表 1 和链表 2,对于链表 1 中的每个节点,依次和链表 2 中的各节点进行比对,查看它们的存储地址是否相同,如果相同,则表明它们相交;反之则表明它们不相交。此算法使用嵌套循环,时间复杂度为O(n2)
//L1 和 L2 为 2 个单链表,函数返回 True 表示链表相交,返回 False 表示不相交
bool LinkIntersect(link * L1, link * L2) {
    link * p1 = L1;
    link * p2 = L2;
    while (p1)  //逐个遍历 L1 链表中的各个节点
    {
        while (p2) {  //遍历 L2 链表,针对每个 p1,依次和 p2 所指节点做比较
            if (p1 == p2) {  //p1、p2 中记录的就是各个节点的存储地址,直接比较即可
                return True;
            }
            p2 = p2->next;
        }
        p1 = p1->next;
    }
    return False;
}
  • 思路2 :2 个单链表相交有一个必然结果,即这 2 个链表相交则最后一个节点必定相同,因此只需要比较两个结点最后一个结点即可。该算法的时间复杂度就缩小为O(n)
//L1 和 L2 为 2 个单链表,函数返回 True 表示链表相交,返回 False 表示不相交
bool LinkIntersect(link * L1, link * L2) {
    link * p1 = L1;
    link * p2 = L2;
    while (p1->next) { //找到 L1 链表中的最后一个节点
        p1 = p1->next;
    }
    while (p2->next) //找到 L2 链表中的最后一个节点
    {
        p2 = p2->next;
    }
    if (p1 == p2) {   //判断 L1 和 L2 链表最后一个节点是否相同
        return True;
    }
    return False;
}
  • 思路3 : r两个链表相交,则部分节点的数量一定是相等的。按照短链表的长度,依次比较每个结点,如果相交则会找到相同的结点。
    在这里插入图片描述
bool LinkIntersect(link * L1, link * L2) {
    link * plong = L1;
    link * pshort = L2;
    link * temp = NULL;
    int num1 = 0, num2 = 0, step = 0;
    while (plong) {   //得到 L1 的长度
        num1++;
        plong = plong->next;
    }
    while (pshort)  //得到 L2 的长度
    {
        num2++;
        pshort = pshort->next;
    }
    //重置plong和pshort,使plong代表较长的链表,pshort代表较短的链表
    plong = L1;
    pshort = L2;
    step = num1 - num2;
    if (num1 < num2) {
        plong = L2;
        pshort = L1;
        step = num2 - num1;
    }
    temp = plong;  //在plong链表中找到和pshort等长度的子链表
    while (step) {
        temp = temp->next;
        step--;
    }
    while (temp && pshort) {   //逐个比较temp和pshort链表中的节点是否相同
        if (temp == pshort) {
            return True;
        }
        temp = temp->next;
        pshort = pshort->next;
    }
    return False;
}

感谢阅读 若有错误 敬请见谅!!!


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

园长QwQ

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

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

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

打赏作者

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

抵扣说明:

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

余额充值