首页 > 编程语言 >算法 | 就地逆置、双指针快速寻找中间节点

算法 | 就地逆置、双指针快速寻找中间节点

时间:2023-08-01 23:24:13浏览次数:31  
标签:LinkList 结点 NULL next 链表 地逆置 节点 指针

2019年真题

设线性表 L=(a1, a2, a3, ..., an-2, an-1, an) 采用带头节点的单链表保存,链表中的结点定义如下:(代码1) 设计一个空间复杂度为O(1) 且时间上尽可能高效的算法,重新排列 L 中的各结,得到线性表 L’=(a1, an, a2, an-1, a3, an-2, ...)。

// 代码1
// lang C
typedef struct node{
  int data;
  struct node*next;
} NODE;

算法思路

  • 使用双指针找到链表的中间结点
  • 对链表的后半部分进行就地逆置
  • 然后与链表前半部分按题目要求混合
// 一些必要的工作
#include <stdio.h>
#include <stdlib.h>
#define ElemType int
#define maxSize 20

typedef struct node{
  ElemType data; // 结点中的数据元素
  struct node*next; // 结点的后继指针
}NODE, *LinkList;
// 初始化带头链表的函数
LinkList InitLinkList(LinkList l){
  l = (NODE*)malloc(sizeof(NODE)); // 创建一个头指针
  l->next = NULL;
  NODE *s; // 创建一个临时变量,用于初始化每一个结点
  NODE *t = NULL; // 用于保存上一个结点 
  for(int i=1; i<=maxSize; i++){
    s = (NODE*)malloc(sizeof(NODE));
    s->data = i;
    s->next = NULL;
    if(t == NULL)
      l->next = s; // 用头指针指向第一个结点
     else
       t->next = s; //上一个结点的后继指针指向当前结点
      t = s; 
  }
  return l;
}
// 使用双指针寻找链表的中间结点
// p指针每次后移一个,q每次后移两个;
// 等到q移动到最后一个元素,此时p指向的就是链表的中间结点
LinkList FindMiddleElme(LinkList p, LinkList q){
  while(q->next != NULL){
    if((q->next->next) != NULL)
      q = q->next->next; // q 后移两个结点
     else
       q = q->next; // 当 q 的后两个结点为空时,则后移一个,防止指针越界
     p = p->next; // 每次循环 p 指针都后移一个 
  }
  return p; // 此时 p 指针指向链表的中间j结点
}
// 就地逆置链表函数
// 使用头插法
// 没啥好说的,头插法逆置
LinkList reverse(LinkList l){
  NODE *p, *s, *h;
  h = (NODE*)malloc(sizeof(NODE));
  p = l; 
  s = p->next;
  h->next = NULL; 
  while(p != NULL){
    p->next = h->next;
    h->next = p;
    p = s;
    if(p != NULL)
      s = p->next;
  }
  return h;
}
// 打印链表函数
// 遍历链表每一个结点并打印元素
void PrintList(LinkList l){
  NODE* s;
  s = l;
  while(s != NULL){
    printf("%d ", s->data);
    s = s->next;
  }
}
// 混合函数
// 规则:L’=(a1, an, a2, an-1, a3, an-2, ...)
// 按照后半部分链表,将后半部分链表的每一个结点插到前边链表中
LinkList mix(LinkList l, LinkList p){
  NODE *s, *r, *m;
  s = p->next; // s 为中间指针,指向为待插入的结点
  p = s->next; // 将 p 指针指向下一个待插入的结点
  m = l->next; // m为中间指针,指向为待插入结点的前驱
  r = m; // 将 r 指向链表头
  while(s->next != NULL){
    s->next = m->next; // 待插入结点的后继指向插入位的后继
    m->next = s; // 插入位的前驱指向 待插入结点
    m = s->next; // 插入位后移
    s = p; // 待插入结点后移
    p = s->next; // 将 p 指针指向下一个待插入的结点
  }  
  return r;
}
// 主函数
int main(){
  LinkList LL = InitLinkList(LL);
  LinkList p = LL->next;
  LinkList q = p;
  
  // 寻找中间结点
  p = FindMiddleElme(p, q);
  
  // 就地逆置链表后半部分
  p = reverse(p);
  
  // 混合链表
  q = mix(LL, p);
  
  // 打印链表
  PrintList(q);
  return 0;
}

运行结果

image





标签:LinkList,结点,NULL,next,链表,地逆置,节点,指针
From: https://www.cnblogs.com/inslog/p/17599409.html

相关文章

  • C++入门到放弃(06)——this指针
    1.基本介绍this本身很容易理解:在C++所有类当中,都将this(关键字)指针设置为当前对象的地址。this本身是指针,*this是变量,类型为当前类的类型。2.举例刚开始看到this指针的时候,总会觉得奇怪,怎么会有这种用法。我们需要当前类的变量以及函数的时候,明明可以直接在类的内部直接调用,......
  • 初学C语言day07--指针与堆内存
    什么是指针:指针是一种特殊的数据类型,使用它可以定义指针变量,指针变量中存储的是整形数据,该整型数据代表了内存的编号(地址),可以通过这个编号访问对应的内存为什么要使用指针:1、函数之间是相互独立的,但是有时候需要共享变量传参是单向值传递全局变量可以共享,但是容易命名冲突......
  • C++函数传递函数指针、仿函数、绑定器、可调用对象
    只定义voidtestFunc(intnum,conststd::function<int(int)>&functor)就可以,其他的相当于这个函数的特化版本#include<iostream>#include<functional>usingnamespacestd;intfunc1(intnum){cout<<"func1:"<<num<<en......
  • 手把手教你解决传说中的NPE空指针异常
    1.前言最近有好几个初学java的小伙伴,甚至是学习到JavaWeb、框架阶段的小伙伴,跑来问健哥,该如何解决Java中的NullPointerException空指针异常。因为NPE是初学者常见的典型异常,所以健哥在这里专门写一篇文章,来手把手地教大家分析解决这个经典异常问题。2.异常现象首先我们来看看......
  • 链表双指针技巧汇总 [labuladong-刷题打卡 day1]
    双指针合并21.合并两个有序链表比较简单的双指针比较算法,两个指针分别指向待合并链表/序列,比较后选择符合条件的指针移动Trick:链表在实现时,带头节点的链表在操作中更方便题解/***Definitionforsingly-linkedlist.*structListNode{*intval;*ListNo......
  • c指针
    指针变量数据类型*指针变量名;int*p;//定义了一个指针变量p,*是用来修饰变量的,说明p是个指针变量,变量名是p在定义指针变量的时候*代表修饰的意思修饰p是个指针变量。关于指针的运算符:&取地址*取值p=&a;//把a的地址给p赋值&是取地址符eg:p=&a;//p保存了a的地址,也可以......
  • C语言---malloc(0)会产生什么结果,真的是空指针吗?
    前言(1)几天前在一个交流群中看到有人说,面试问malloc(0)会怎么样是真的恶心。(2)这个突然激起了我的好奇心。居然还可以malloc(0)?!(3)经过测试最后,发现是可行的。经过互联网的查找,肯哥的交流群以及自己的理解,梳理成这篇博客。(4)肯哥博客主页:架构师李肯;(5)感慨一下,群里面的大佬们不愧是有......
  • mongodb 隐藏节点 查看
    MongoDB隐藏节点查看步骤概述在MongoDB中,隐藏节点是指那些不参与主节点选举,但可以用于读操作的节点。隐藏节点对于搭建高可用的数据库架构以及优化读取性能非常重要。本文将介绍如何在MongoDB中查看隐藏节点。步骤步骤操作步骤一连接到MongoDB实例步骤二查看复制......
  • 代码随想录第四天|力扣24.两两交换链表节点、力扣19.删除链表的倒数第N个结点、力扣面
    两两交换链表中的节点(力扣24.)dummyhead.next=head;cur=dummyhead;while(cur.next!=null&&cur.next.next!=null)temp=cur.next;temp1=cur.next.next.next;cur.next=cur.next.next;cur.next.next=temp;temp.next=temp1;cur=cur.next.next;returndummyhead.n......
  • 代码随想录算法训练营第四天| LeetCode 24. 两两交换链表中的节点 19.删除链表的倒
    24.两两交换链表中的节点     卡哥建议:用虚拟头结点,这样会方便很多。 本题链表操作就比较复杂了,建议大家先看视频,视频里我讲解了注意事项,为什么需要temp保存临时节点。   题目链接/文章讲解/视频讲解:https://programmercarl.com/0024.%E4%B8%A4%E4%B8%A4%E4%BA%......