目录

  • 反转单链表
    • 1.递归反转整个链表
    • 2.反转链表前 N 个节点
    • 3.反转链表的一部分
    • 整代码
  • K 个一组反转链表
    • 迭代法反转
    • 整代码
  • 判断回文单链表
    • 后序递归方式
    • 空间复杂度优化 O(N)->O(1)
    • 整代码

反转单链表

对于递归算法,最重要的就是明确递归函数的定义
reverseAll 函数定义:输入一个节点head,将「以head为起点」的链表反转,并返回反转之后的头结点

链接
节点结构:

typedef int elemtype;
typedef struct node{elemtype data;struct node *next;
}node,*link_node;

1.递归反转整个链表

link_node reverseAll(link_node head){if(head->next == NULL) return head;link_node new_head=reverseAll(head->next);head->next->next = head;head->next = NULL;return new_head;
}

2.反转链表前 N 个节点

link_node successor = NULL;
link_node reverseN(link_node head,int n){if(n==1){successor =  head->next;return head;}link_node new_n_head = reverseN(head->next,n-1);head->next->next = head;head->next = successor;return new_n_head;
}

3.反转链表的一部分

问题转换,将该问题转换成反转前n节点

link_node reverseBetween(link_node head,int m,int n){ // [m,n]if(m==1){return reverseN(head,n);}head->next = reverseBetween(head->next,m-1,n-1);return head;
}

整代码

#include<iostream>
using namespace std;typedef int elemtype;
typedef struct node{elemtype data;struct node *next;
}node,*link_node;void create_node_list(link_node head) {link_node p, q;elemtype array[] = {1,2,3,4,5,6,7,8,9,10};int length = sizeof(array) / sizeof(array[0]);q = head;head->data = length;head->next = NULL;for (int i = 0; i < length; i++) {p = new node;p->data = array[i];p->next = NULL; // 尾插法q->next = p;q = p;}
}
void out_elem(node head_node) {link_node p = head_node.next;while (p) {cout << p->data << ' ';p = p->next;}cout << endl;
}link_node reverseAll(link_node head);
link_node reverseN(link_node head,int n);
link_node reverseBetween(link_node head,int m,int n);
int main(){node head_node; // 头节点cout<<"原链表"<<endl;create_node_list(&head_node);out_elem(head_node);cout<<"完全反转"<<endl;head_node.next=reverseAll(head_node.next);out_elem(head_node);cout<<"反转前N个:4"<<endl;head_node.next=reverseN(head_node.next,4);out_elem(head_node);cout<<"反转一部分[5-9]"<<endl;head_node.next=reverseBetween(head_node.next,5,9);out_elem(head_node);return 0;
}link_node reverseAll(link_node head){if(head->next == NULL) return head;link_node new_head=reverseAll(head->next);head->next->next = head;head->next = NULL;return new_head;
}link_node successor = NULL;
link_node reverseN(link_node head,int n){if(n==1){successor =  head->next;return head;}link_node new_n_head = reverseN(head->next,n-1);head->next->next = head;head->next = successor;return new_n_head;
}link_node reverseBetween(link_node head,int m,int n){ // [m,n]if(m==1){return reverseN(head,n);}head->next = reverseBetween(head->next,m-1,n-1);return head;
}

K 个一组反转链表

链接

问题剖析:
该问题属于迭代问题:前n个节点反转,剩余链表继续对前n个节点反转(子问题)

reverseKGroup 函数定义: 对前n个节点进行反转 ; 反转后的节点与剩余链表进行拼接
递归终止条件:剩余链表元素个数少于 k 个

link_node reverseKGroup(link_node head, int k) {if (head == NULL) return head;link_node a, b;a = b = head;for (int i = 0; i < k; i++) {if (b == NULL) return head;b = b->next;}// 反转前k个link_node new_=reverseIteration(a, b);a->next = reverseKGroup(b, k);return new_;
}

迭代法反转

link_node reverseIteration(link_node a, link_node b) { // [a,b)link_node pre, cur, nxt;pre = NULL; cur = nxt = a;while (cur != b) {nxt = cur->next;cur->next = pre;pre = cur;cur = nxt;}return pre;
}

整代码

#include<iostream>
using namespace std;typedef int elemtype;
typedef struct node {elemtype data;struct node* next;
} node, *link_node;void creatListNode(link_node head);
void outElem(link_node head);
link_node reverseKGroup(link_node head, int k);
link_node reverseIteration(link_node a, link_node b);
int main() {node head_node;cout << "原链表" << endl;creatListNode(&head_node);outElem(&head_node);cout << "k个元素一组反转:3" << endl;head_node.next=reverseKGroup(head_node.next,3);outElem(&head_node);return 0;
}void creatListNode(link_node head) {link_node p, q;elemtype arr[] = { 1,2,3,4,5,6,7,8,9,10};int length = sizeof(arr) / sizeof(arr[0]);head->data = length;head->next = NULL;q = head;for (int i = 0; i < length; i++) {p = new node;p->data = arr[i];p->next = NULL;q->next = p;q = p;}
}
void outElem(link_node head) {link_node p = head->next;while (p) {cout << p->data << ' ';p = p->next;}cout << endl;
}link_node reverseKGroup(link_node head, int k) {if (head == NULL) return head;link_node a, b; // 窗口指针a = b = head;for (int i = 0; i < k; i++) {if (b == NULL) return head;b = b->next;}// 反转前k个// 剩余链表段的头部;第一层递归即整个链表的新头部link_node new_=reverseIteration(a, b);// 反转后 a 为反转链表的尾部,与剩余链表 连接a->next = reverseKGroup(b, k); return new_;
}
link_node reverseIteration(link_node a, link_node b) { // [a,b)link_node pre, cur, nxt;pre = NULL; cur = nxt = a;while (cur != b) {nxt = cur->next;cur->next = pre;pre = cur;cur = nxt;}return pre;
}

判断回文单链表

链接

回文串就是正着读和反着读都一样的字符串
寻找回文串的核心思想是从中心向两端扩展

后序递归方式

link_node left_=NULL;
bool isPalindrome(link_node head) {left_ = head;return traverse(left_);
}bool traverse(link_node right) {if (right == NULL) return true;bool res = traverse(right->next);// 后序遍历res = res && (right->data == left_->data);left_ = left_->next;return res;
}

空间复杂度优化 O(N)->O(1)

由于上述代码采用递归方式判断回文链表,须额外的栈空间,空间复杂度为O(N)

优化代码:
采用 快慢指针 找到链表 中点 (慢指针 单步,快指针 2步) ; 通过判断快指针是否满足(fast!=null 且 fast->next != null) ,看是否找到中点(slow指向)
后半段 链表进行反转
定义 left right 两指针向中间遍历比较;

bool isPalindromeOptimize(link_node head) { // 快慢指针link_node fast, slow;link_node p,q; // 用于复原 链表结构; p,q 分别指向需反转链表段的首尾 p = NULL; // 注释 会提示未初始化变量 ; // 因为 p 的初始化都放在 存在判断语句的表示式中,在p->next位置会提示未初始化变量fast = slow = head;while (fast != NULL&&fast->next != NULL) { // 奇偶数 p = slow;  // 用于元素个数为偶数时 slow = slow->next;  // 一步fast = fast->next->next; //两步} if (fast != NULL) {p = slow; // 用于元素个数为奇数时 ; 注意 p 指向,易成环slow = slow->next; // 奇数时,循环结束low指向中间元素,需右移一步}// 反转后半部分链表 link_node left_ = head;link_node right = reverse(slow); // 改变了原链表结构q = right;while (right != NULL) {if (left_->data != right->data) {p->next = reverse(q);return false;}left_ = left_->next;right = right->next;}p->next = reverse(q); // 还原链表结构return true;
}link_node reverse(link_node head) {link_node pre, cur, nxt;pre = NULL; cur = nxt = head;while (cur != NULL) {nxt = cur->next;cur->next = pre;pre = cur;cur = nxt;}return pre;
}

整代码

#include<iostream>
using namespace std;typedef int elemtype;
typedef struct node {elemtype data;struct node* next;
} node, *link_node;void creatListNode(link_node head);
void outElem(link_node head);
bool isPalindrome(link_node head);
bool traverse(link_node right);
bool isPalindromeOptimize(link_node head);
link_node reverse(link_node head);int main() {node head_node;cout << "原链表" << ' ';creatListNode(&head_node);outElem(&head_node);cout << "是否为回文链表: ";isPalindrome(head_node.next) ? cout << "True" << endl : cout << "False" << endl;cout << "优化后: ";isPalindromeOptimize(head_node.next) ? cout << "True" << endl : cout << "False" << endl;cout << "修改后复原: " ;outElem(&head_node);return 0;
}void creatListNode(link_node head) {link_node p, q;elemtype arr[] = {1,2,3,4,6,5,4,3,2,1};int length = sizeof(arr) / sizeof(arr[0]);head->data = length;head->next = NULL;q = head;for (int i = 0; i < length; i++) {p = new node;p->data = arr[i];p->next = NULL;q->next = p;q = p;}
}
void outElem(link_node head) {link_node p = head->next;while (p) {cout << p->data << ' ';p = p->next;}cout << endl;
}link_node left_=NULL;
bool isPalindrome(link_node head) {left_ = head;return traverse(left_);
}bool traverse(link_node right) {if (right == NULL) return true;bool res = traverse(right->next);// 后序遍历res = res && (right->data == left_->data);left_ = left_->next;return res;
}bool isPalindromeOptimize(link_node head) { // 快慢指针link_node fast, slow;link_node p,q; // 用于复原 链表结构; p,q 分别指向需反转链表段的首尾 p = NULL; // 注释 会提示未初始化变量 ; // 因为 p 的初始化都放在 存在判断语句的表示式中,在p->next位置会提示未初始化变量fast = slow = head;while (fast != NULL&&fast->next != NULL) { // 奇偶数 p = slow;  // 用于元素个数为偶数时 slow = slow->next;    // 一步fast = fast->next->next; //两步} if (fast != NULL) {p = slow; // 用于元素个数为奇数时 ; 注意 p 指向,易成环slow = slow->next; // 奇数时,循环结束low指向中间元素,需右移一步}// 反转后半部分链表 link_node left_ = head;link_node right = reverse(slow); // 改变了原链表结构q = right;while (right != NULL) {if (left_->data != right->data) {p->next = reverse(q);return false;}left_ = left_->next;right = right->next;}p->next = reverse(q); // 还原链表结构return true;
}link_node reverse(link_node head) {link_node pre, cur, nxt;pre = NULL; cur = nxt = head;while (cur != NULL) {nxt = cur->next;cur->next = pre;pre = cur;cur = nxt;}return pre;
}

偶数个数:

奇数个数:

非回文链表:

C++中substr函数的用法

Leecode 入门--单链表-- 递归操作相关推荐

  1. java实现单链表常见操作,java面试题,java初级笔试题

    写在最前面,我总结出了很多互联网公司的面试题及答案,并整理成了文档,以及各种学习的进阶学习资料,免费分享给大家.扫码加微信好友进[程序员面试学习交流群],免费领取.也欢迎各位一起在群里探讨技术. 一. ...

  2. java实现单链表常见操作

    一.概述: 本文主要总结单链表常见操作的实现,包括链表结点添加.删除:链表正向遍历和反向遍历.链表排序.判断链表是否有环.是否相交.获取某一结点等. 二.概念: 链表: 一种重要的数据结构,HashM ...

  3. 笔试面试常考数据结构-单链表常用操作编程实现

    单链表是笔试以及面试手写代码中常考的数据结构之一.下面实现了单链表的常见操作:创建单链表.删除节点.打印单链表(包括正向打印以及逆向打印).反转单链表.找出单链表的倒数第K个节点.合并两个有序单链表等 ...

  4. 单链表创建及代码实现对单链表的操作

    链表:链表是一个有序的列表:是以节点的方式存储的,是链式存储:其中每一个节点包含data域,next域,next域指向下一个节点:链表的各个节点不一定是连续存放的:链表分带有头节点的链表和没有头节点的 ...

  5. 数据结构(5)之单链表的操作(补充)

    1 前言 上次我们讲到单链表的存储和一些简单的算法,今天我们来学习一下单链表的初始化和销毁操作. 2 详述 2.1 单链表的整表创建 思路: ·声明一结点p和计数器变量i; ·初始化一空链表L: ·让 ...

  6. c语言单链表数据显示,C++_C语言单链表常见操作汇总,C语言的单链表是常用的数据结 - phpStudy...

    #include #include //定义单链表结构体 typedef int ElemType; typedef struct Node { ElemType data; struct Node ...

  7. Java实现单链表反转操作

    单链表是一种常见的数据结构,由一个个节点通过指针方式连接而成,每个节点由两部分组成:一是数据域,用于存储节点数据.二是指针域,用于存储下一个节点的地址.在Java中定义如下: public class ...

  8. python 单链表的操作

    链表由一系列不必在内存中相连的结构构成,这些对象按线性顺序排序.每个结构含有表元素和指向后继元素的指针.最后一个单元的指针指向NULL.为了方便链表的删除与插入操作,可以为链表添加一个表头. 单链表 ...

  9. 逆置单链表——递归与非递归

    文章目录 前言 方式一:非递归 原理 图解 实现代码 方式二:递归 原理 图解 实现代码 完整实现 代码 运行结果 前言 单链表的逆置图解 方式一:非递归 原理 非递归逆置单链表的本质是创建一个新的链 ...

最新文章

  1. Delphi指针用法
  2. JavaScript学习代码整理(二)--函数
  3. 3V、5V混合系统中不同电平器件接口的4种情况
  4. 新手Ubuntu 分子动力学模拟软件 Gromacs 安装教程!
  5. matlab更改安全密钥,Linux下设置安全密钥登录
  6. python中的chardet模块
  7. 黑马程序员—我的面试,我的学习,我的经历
  8. 正则表达式与自动机c语言,用有限自动机实现正则表达式的匹配
  9. UE4 虚幻引擎,处理PBR材质
  10. IDEA中Python使用url时报错:Traceback (most recent call last)
  11. 对伪元素::after和::before的理解
  12. oracle yum配置本地源,oel 7 本地yum源配置
  13. 今日卢布美元汇率换算
  14. 停车、投票、领证,区块链如何在「智慧城市」建设中大显身手?
  15. 动词ing基本用法_动词-ing的形式及用法
  16. HKEY_CURRENT_USER下在服务中注册自启动exe
  17. 使用nsis制作的安装包安装后,无法卸载干净的问题
  18. ThreeJS绘制流动的虚线效果
  19. 【K8S 三】部署 metrics-server 插件
  20. OP-TEE内核学习笔记(一)(安全存储)—— 密钥和文件结构

热门文章

  1. 大数据分析对企业起到什么作用
  2. 如何建立完整的数据治理体系
  3. splice方法_Array中splice用法
  4. 数据结构括号匹配代码_数据结构中的栈,你知道多少?
  5. Linux登录日志配置,Unix系统用户登录及操作命令日志配置的方法
  6. php上传虚假图片,解决PHP上传多个图片并校验的代码问题
  7. 2021年SWPUACM暑假集训day4KMP算法
  8. java什么叫用例_BigInteger的.isProbablePrime()的可能用例是什么?
  9. windows mysql 自动备份_windows mysql 自动备份的几种方法总结--岁月博客提供
  10. java jdk7 环境变量设置_Java JDK7在Windows 8下的环境变量配置