算法刷题-双指针-反转链表

news2024/11/15 17:15:39

反转链表的写法很简单,一些同学甚至可以背下来但过一阵就忘了该咋写,主要是因为没有理解真正的反转过程。

206.反转链表

力扣题目链接

题意:反转一个单链表。

示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

思路

如果再定义一个新的链表,实现链表元素的反转,其实这是对内存空间的浪费。

其实只需要改变链表的next指针的指向,直接将链表反转 ,而不用重新定义一个新的链表,如图所示:

206_反转链表

之前链表的头节点是元素1, 反转之后头结点就是元素5 ,这里并没有添加或者删除节点,仅仅是改变next指针的方向。

那么接下来看一看是如何反转的呢?

我们拿有示例中的链表来举例,如动画所示:(纠正:动画应该是先移动pre,在移动cur)

在这里插入图片描述

首先定义一个cur指针,指向头结点,再定义一个pre指针,初始化为null。

然后就要开始反转了,首先要把 cur->next 节点用tmp指针保存一下,也就是保存一下这个节点。

为什么要保存一下这个节点呢,因为接下来要改变 cur->next 的指向了,将cur->next 指向pre ,此时已经反转了第一个节点了。

接下来,就是循环走如下代码逻辑了,继续移动pre和cur指针。

最后,cur 指针已经指向了null,循环结束,链表也反转完毕了。 此时我们return pre指针就可以了,pre指针就指向了新的头结点。

C++代码

双指针法

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* temp; // 保存cur的下一个节点
        ListNode* cur = head;
        ListNode* pre = NULL;
        while(cur) {
            temp = cur->next;  // 保存一下 cur的下一个节点,因为接下来要改变cur->next
            cur->next = pre; // 翻转操作
            // 更新pre 和 cur指针
            pre = cur;
            cur = temp;
        }
        return pre;
    }
};

递归法

递归法相对抽象一些,但是其实和双指针法是一样的逻辑,同样是当cur为空的时候循环结束,不断将cur指向pre的过程。

关键是初始化的地方,可能有的同学会不理解, 可以看到双指针法中初始化 cur = head,pre = NULL,在递归法中可以从如下代码看出初始化的逻辑也是一样的,只不过写法变了。

具体可以看代码(已经详细注释),双指针法写出来之后,理解如下递归写法就不难了,代码逻辑都是一样的。

class Solution {
public:
    ListNode* reverse(ListNode* pre,ListNode* cur){
        if(cur == NULL) return pre;
        ListNode* temp = cur->next;
        cur->next = pre;
        // 可以和双指针法的代码进行对比,如下递归的写法,其实就是做了这两步
        // pre = cur;
        // cur = temp;
        return reverse(cur,temp);
    }
    ListNode* reverseList(ListNode* head) {
        // 和双指针法初始化是一样的逻辑
        // ListNode* cur = head;
        // ListNode* pre = NULL;
        return reverse(NULL, head);
    }

};

我们可以发现,上面的递归写法和双指针法实质上都是从前往后翻转指针指向,其实还有另外一种与双指针法不同思路的递归写法:从后往前翻转指针指向。

具体代码如下(带详细注释):

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        // 边缘条件判断
        if(head == NULL) return NULL;
        if (head->next == NULL) return head;
        
        // 递归调用,翻转第二个节点开始往后的链表
        ListNode *last = reverseList(head->next);
        // 翻转头节点与第二个节点的指向
        head->next->next = head;
        // 此时的 head 节点为尾节点,next 需要指向 NULL
        head->next = NULL;
        return last;
    }
}; 

其他语言版本

Java:

// 双指针
class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode prev = null;
        ListNode cur = head;
        ListNode temp = null;
        while (cur != null) {
            temp = cur.next;// 保存下一个节点
            cur.next = prev;
            prev = cur;
            cur = temp;
        }
        return prev;
    }
}
// 递归 
class Solution {
    public ListNode reverseList(ListNode head) {
        return reverse(null, head);
    }

    private ListNode reverse(ListNode prev, ListNode cur) {
        if (cur == null) {
            return prev;
        }
        ListNode temp = null;
        temp = cur.next;// 先保存下一个节点
        cur.next = prev;// 反转
        // 更新prev、cur位置
        // prev = cur;
        // cur = temp;
        return reverse(cur, temp);
    }
}
// 从后向前递归
class Solution {
    ListNode reverseList(ListNode head) {
        // 边缘条件判断
        if(head == null) return null;
        if (head.next == null) return head;
        
        // 递归调用,翻转第二个节点开始往后的链表
        ListNode last = reverseList(head.next);
        // 翻转头节点与第二个节点的指向
        head.next.next = head;
        // 此时的 head 节点为尾节点,next 需要指向 NULL
        head.next = null;
        return last;
    } 
}

Python迭代法:

#双指针
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        cur = head   
        pre = None
        while(cur!=None):
            temp = cur.next # 保存一下 cur的下一个节点,因为接下来要改变cur->next
            cur.next = pre #反转
            #更新pre、cur指针
            pre = cur
            cur = temp
        return pre

Python递归法:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        
        def reverse(pre,cur):
            if not cur:
                return pre
                
            tmp = cur.next
            cur.next = pre

            return reverse(cur,tmp)
        
        return reverse(None,head)

Python递归法从后向前:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        if not head or not head.next: return head
        p = self.reverseList(head.next)
        head.next.next = head
        head.next = None
        return p

Go:

//双指针
func reverseList(head *ListNode) *ListNode {
    var pre *ListNode
    cur := head
    for cur != nil {
        next := cur.Next
        cur.Next = pre
        pre = cur
        cur = next
    }
    return pre
}

//递归
func reverseList(head *ListNode) *ListNode {
    return help(nil, head)
}

func help(pre, head *ListNode)*ListNode{
    if head == nil {
        return pre
    }
    next := head.Next
    head.Next = pre
    return help(head, next)
}

javaScript:

/**
 * @param {ListNode} head
 * @return {ListNode}
 */

// 双指针:
var reverseList = function(head) {
    if(!head || !head.next) return head;
    let temp = null, pre = null, cur = head;
    while(cur) {
        temp = cur.next;
        cur.next = pre;
        pre = cur;
        cur = temp;
    }
    // temp = cur = null;
    return pre;
};

// 递归:
var reverse = function(pre, head) {
    if(!head) return pre;
    const temp = head.next;
    head.next = pre;
    pre = head
    return reverse(pre, temp);
}

var reverseList = function(head) {
    return reverse(null, head);
};

// 递归2
var reverse = function(head) {
    if(!head || !head.next) return head;
    // 从后往前翻
    const pre = reverse(head.next);
    head.next = pre.next;
    pre.next = head;
    return head;
}

var reverseList = function(head) {
    let cur = head;
    while(cur && cur.next) {
        cur = cur.next;
    }
    reverse(head);
    return cur;
};

TypeScript:

// 双指针法
function reverseList(head: ListNode | null): ListNode | null {
    let preNode: ListNode | null = null,
        curNode: ListNode | null = head,
        tempNode: ListNode | null;
    while (curNode) {
        tempNode = curNode.next;
        curNode.next = preNode;
        preNode = curNode;
        curNode = tempNode;
    }
    return preNode;
};

// 递归(从前往后翻转)
function reverseList(head: ListNode | null): ListNode | null {
    function recur(preNode: ListNode | null, curNode: ListNode | null): ListNode | null {
        if (curNode === null) return preNode;
        let tempNode: ListNode | null = curNode.next;
        curNode.next = preNode;
        preNode = curNode;
        curNode = tempNode;
        return recur(preNode, curNode);
    }
    return recur(null, head);
};

// 递归(从后往前翻转)
function reverseList(head: ListNode | null): ListNode | null {
    if (head === null) return null;
    let newHead: ListNode | null;
    function recur(node: ListNode | null, preNode: ListNode | null): void {
        if (node.next === null) {
            newHead = node;
            newHead.next = preNode;
        } else {
            recur(node.next, node);
            node.next = preNode;
        }
    }
    recur(head, null);
    return newHead;
};

Ruby:

# 双指针
# Definition for singly-linked list.
# class ListNode
#     attr_accessor :val, :next
#     def initialize(val = 0, _next = nil)
#         @val = val
#         @next = _next
#     end
# end
def reverse_list(head)
  # return nil if head.nil?	# 循环判断条件亦能起到相同作用因此不必单独判断
  cur, per = head, nil
  until cur.nil?
    tem = cur.next
    cur.next = per
    per = cur
    cur = tem
  end
  per
end

# 递归
# Definition for singly-linked list.
# class ListNode
#     attr_accessor :val, :next
#     def initialize(val = 0, _next = nil)
#         @val = val
#         @next = _next
#     end
# end
def reverse_list(head)
  reverse(nil, head)
end

def reverse(pre, cur)
  return pre if cur.nil?
  tem = cur.next
  cur.next = pre
  reverse(cur, tem)	# 通过递归实现双指针法中的更新操作
end

Kotlin:

fun reverseList(head: ListNode?): ListNode? {
    var pre: ListNode? = null
    var cur = head
    while (cur != null) {
        val temp = cur.next
        cur.next = pre
        pre = cur
        cur = temp
    }
    return pre
}
/**
 * Example:
 * var li = ListNode(5)
 * var v = li.`val`
 * Definition for singly-linked list.
 * class ListNode(var `val`: Int) {
 *     var next: ListNode? = null
 * }
 */
class Solution {
    fun reverseList(head: ListNode?): ListNode? {
        // temp用来存储临时的节点
        var temp: ListNode?
        // cur用来遍历链表
        var cur: ListNode? = head
        // pre用来作为链表反转的工具
        // pre是比pre前一位的节点
        var pre: ListNode? = null
        while (cur != null) {
            // 临时存储原本cur的下一个节点
            temp = cur.next
            // 使cur下一节点地址为它之前的
            cur.next = pre
            // 之后随着cur的遍历移动pre
            pre = cur;
            // 移动cur遍历链表各个节点
            cur = temp;
        }
        // 由于开头使用pre为null,所以cur等于链表本身长度+1,
        // 此时pre在cur前一位,所以此时pre为头节点
        return pre;
    }
}

Swift:

/// 双指针法 (迭代)
/// - Parameter head: 头结点
/// - Returns: 翻转后的链表头结点
func reverseList(_ head: ListNode?) -> ListNode? {
    if head == nil || head?.next == nil {
        return head
    }
    var pre: ListNode? = nil
    var cur: ListNode? = head
    var temp: ListNode? = nil
    while cur != nil {
        temp = cur?.next
        cur?.next = pre
        pre = cur
        cur = temp
    }
    return pre
}

/// 递归
/// - Parameter head: 头结点
/// - Returns: 翻转后的链表头结点
func reverseList2(_ head: ListNode?) -> ListNode? {
    return reverse(pre: nil, cur: head)
}
func reverse(pre: ListNode?, cur: ListNode?) -> ListNode? {
    if cur == nil {
        return pre
    }
    let temp: ListNode? = cur?.next
    cur?.next = pre
    return reverse(pre: cur, cur: temp)
}

C:
双指针法:

struct ListNode* reverseList(struct ListNode* head){
    //保存cur的下一个结点
    struct ListNode* temp;
    //pre指针指向前一个当前结点的前一个结点
    struct ListNode* pre = NULL;
    //用head代替cur,也可以再定义一个cur结点指向head。
    while(head) {
        //保存下一个结点的位置
        temp = head->next;
        //翻转操作
        head->next = pre;
        //更新结点
        pre = head;
        head = temp;
    }
    return pre;
}

递归法:

struct ListNode* reverse(struct ListNode* pre, struct ListNode* cur) {
    if(!cur)
        return pre;
    struct ListNode* temp = cur->next;
    cur->next = pre;
    //将cur作为pre传入下一层
    //将temp作为cur传入下一层,改变其指针指向当前cur
    return reverse(cur, temp);
}

struct ListNode* reverseList(struct ListNode* head){
    return reverse(NULL, head);
}

PHP:

// 双指针法:
function reverseList($head) {
    $cur = $head;
    $pre = NULL;
    while($cur){
        $temp = $cur->next; 
        $cur->next = $pre;
        $pre = $cur;
        $cur = $temp;
    }
    return $pre;
    }

Scala:
双指针法:

object Solution {
  def reverseList(head: ListNode): ListNode = {
    var pre: ListNode = null
    var cur = head
    while (cur != null) {
      var tmp = cur.next
      cur.next = pre
      pre = cur
      cur = tmp
    }
    pre
  }
}

递归法:

object Solution {
  def reverseList(head: ListNode): ListNode = {
    reverse(null, head)
  }

  def reverse(pre: ListNode, cur: ListNode): ListNode = {
    if (cur == null) {
      return pre    // 如果当前cur为空,则返回pre
    }
    val tmp: ListNode = cur.next
    cur.next = pre
    reverse(cur, tmp)   // 此时cur成为前一个节点,tmp是当前节点
  }

}

Rust:
双指针法:

impl Solution {
    pub fn reverse_list(head: Option<Box<ListNode>>) -> Option<Box<ListNode>> {
        let mut cur = head;
        let mut pre = None;
        while let Some(mut node) = cur.take() {
            cur = node.next;
            node.next = pre;
            pre = Some(node);
        }
        pre
    }
}

递归法:

impl Solution {
    pub fn reverse_list(head: Option<Box<ListNode>>) -> Option<Box<ListNode>> {
        fn rev(
            mut head: Option<Box<ListNode>>,
            mut pre: Option<Box<ListNode>>,
        ) -> Option<Box<ListNode>> {
            if let Some(mut node) = head.take() {
                let cur = node.next;
                node.next = pre;
                pre = Some(node);
                return rev(cur, pre);
            }
            pre
        }
        rev(head, None)
    }
}

C#:
三指针法, 感觉会更直观:

public LinkNumbers Reverse()
{
    ///用三指针,写的过程中能够弥补二指针在翻转过程中的想象
    LinkNumbers pre = null;
    var move = root;
    var next = root;

    while (next != null)
    {
        next = next.linknext;
        move.linknext = pre;
        pre = move;
        move = next;
    }
    root = pre;
    return root;
}

///LinkNumbers的定义
public class LinkNumbers
{
    /// <summary>
    /// 链表值
    /// </summary>
    public int value { get; set; }

    /// <summary>
    /// 链表指针
    /// </summary>
    public LinkNumbers linknext { get; set; }
}

使用虚拟头结点解决链表翻转

使用虚拟头结点,通过头插法实现链表的翻转(不需要栈)

// 迭代方法:增加虚头结点,使用头插法实现链表翻转
public static ListNode reverseList1(ListNode head) {
    // 创建虚头结点
    ListNode dumpyHead = new ListNode(-1);
    dumpyHead.next = null;
    // 遍历所有节点
    ListNode cur = head;
    while(cur != null){
        ListNode temp = cur.next;
        // 头插法
        cur.next = dumpyHead.next;
        dumpyHead.next = cur;
        cur = temp;
    }
    return dumpyHead.next;
}

使用栈解决反转链表的问题

  • 首先将所有的结点入栈
  • 然后创建一个虚拟虚拟头结点,让cur指向虚拟头结点。然后开始循环出栈,每出来一个元素,就把它加入到以虚拟头结点为头结点的链表当中,最后返回即可。
public ListNode reverseList(ListNode head) {
    // 如果链表为空,则返回空
    if (head == null) return null;
    // 如果链表中只有只有一个元素,则直接返回
    if (head.next == null) return head;
    // 创建栈 每一个结点都入栈
    Stack<ListNode> stack = new Stack<>();
    ListNode cur = head;
    while (cur != null) {
        stack.push(cur);
        cur = cur.next;
    }
    // 创建一个虚拟头结点
    ListNode pHead = new ListNode(0);
    cur = pHead;
    while (!stack.isEmpty()) {
        ListNode node = stack.pop();
        cur.next = node;
        cur = cur.next;
    }
    // 最后一个元素的next要赋值为空
    cur.next = null;
    return pHead.next;
}

采用这种方法需要注意一点。就是当整个出栈循环结束以后,cur正好指向原来链表的第一个结点,而此时结点1中的next指向的是结点2,因此最后还需要cur.next = null
image-20230117195418626

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/658555.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AMD CPU微架构分析

一、SoC架构 1.1 整体架构 Zeppelin 参考链接&#xff1a;wikichip: Zeppelin 通过infinity fabric总线将单die分成多die的SoC架构&#xff0c;每个Die包含两个CPU核&#xff08;CCX&#xff09;、2各DDR通道、USB、低功耗IO以及多个IFOP和IFIS serdes接口。 如下所述中&…

干翻Mybatis源码系列之第十篇:Mybatis Plugins基本概念与拦截概述

给自己的每日一句 不从恶人的计谋&#xff0c;不站罪人的道路&#xff0c;不坐亵慢人的座位&#xff0c;惟喜爱耶和华的律法&#xff0c;昼夜思想&#xff0c;这人便为有福&#xff01;他要像一棵树栽在溪水旁&#xff0c;按时候结果子&#xff0c;叶子也不枯干。凡他所做的尽…

vue jointjs 拓扑图 自定义shape 按需引入

只展示部分核心代码&#xff0c;完整代码见文章尾部连接 import jointjs/dist/joint.core.css;// 类库 包含: Paper Graph Cell CellView Element Link 等等 import { dia } from jointjs/src/core.mjs; // 样式库 包含多个分组(basic standard custom ...) import * as standa…

基于Hexo和Butterfly创建个人技术博客,(11) 使用插件增强博客站点能力

Butterfly官方网站&#xff0c;请 点击进入 本章目标&#xff1a; 掌握常用的plugin插件的用法&#xff0c;本文中是butterfly主题内置集成的第三方插件(部分插件需要再次安装)&#xff1b; 一、建议开启的三方插件 KaTeX-数学公式 katex:enable: true# true 表示每一页都加载…

C# NX二次开发:通过UFUN函数获取刀具描述,目录号,库号等信息

今天要将的是&#xff0c;在NX中对CAM模块进行二次开发的时候&#xff0c;往往需要获取一些关于刀具使用的信息&#xff0c;这些信息用NXOPEN的的方法录制也可以录制出来&#xff0c;但是录制出来的代码&#xff0c;往往都是一种刀具类型会出现一个Builder。这样在你不知道有多…

淘宝买家订单API

目录 下载安装与运行 支持的订单读取方式 请求数据格式一 请求头示例 数据格式说明 数据格式示例 返回数据格式一 返回头示例 数据格式说明 数据格式示例 请求数据格式二&#xff08;根据订单编号&#xff09; 请求头示例 返回数据格式二&#xff08;根据订单编号…

【随笔记】如何获得铁粉(仅供参考)

文章目录 一、前言二、秘籍2.1 良好的个人简介2.2 统一的文章格式2.3 详细的专栏划分2.4 有序的博客排版2.4.1 目录部分2.4.2 正文部分2.4.2.1 标题分级2.4.2.2 正文分段2.4.2.3 善用多级列表2.4.2.4 章节分割 三、总结 一、前言 在这篇随笔记的开始&#xff0c;我想声明一下&a…

ChatGPT将改变教育,而不是摧毁它

01 学校和大学的反应迅速而果断 就在 OpenAI 于 2022 年 11月下旬发布ChatGPT 的几天后&#xff0c;该聊天机器人被广泛谴责为一种免费的论文写作、应试工具&#xff0c;它很容易在作业中作弊。 美国第二大学区洛杉矶联合大学立即阻止了OpenAI网站从其学校网络访问。其他人很…

【Java】Java核心要点总结 67

文章目录 1. 浮点数运运算会有精度损失2. 构造方法特点 & 不能被重写3. 接口和抽象类的异同4. Object 类的常见方法5. hashCode() 有什么用 为什么要有 hashCode() 1. 浮点数运运算会有精度损失 这个和计算机保存浮点数的机制有很大关系。我们知道计算机是二进制的&#x…

面试时一定要确认该岗位的直属领导是否在场,如果不在,千万不要接offer,有坑!...

对于有心人来说&#xff0c;面试时可以看出许多隐形信息&#xff0c;比如下面这位网友的提醒&#xff1a; 面试时一定要确认这个岗位的直接汇报领导是否参与了面试&#xff0c;如果没有参与&#xff0c;千万不要接offer&#xff01; 该职位的直接领导不参与面试&#xff0c;只能…

NLP——Topic Modelling

文章目录 A Brief History of Topic ModelsLatent Dirichlet Allocation &#xff08;LDA&#xff09;潜在狄利克雷分布核心思想LDA inputLDA output LDA 如何学习Sampling-based mothods 基于采样的方法Infer Topics For New Documents超参数 Variational methods 变分方法 Ev…

java协同过滤算法的校园二手图书网站springboot vue

用户&#xff1a;&#xff08;商品推荐算法&#xff09; 1)首页主要由导航栏、图书展示页、分页所组成。访客能浏览网站上的待出售图书的信息&#xff0c;但是若要购买&#xff0c;收藏图书&#xff0c;查看卖家信息则会自动跳转到登录界面&#xff0c;已经登录的用户则可以浏…

WPS AI最全申请与使用手册;AIGC制作游戏音乐;便宜快捷使用完整版SD;人人都能看懂的ChatGPT原理课 | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; &#x1f916; 面向虚拟世界的生成式AI市场全景图 作者在这篇文章中探讨了生成式AI在虚拟世界的应用&#xff0c;并绘制了 Market Map V3.0 (市场全景…

C++ 有用的资源||19道必须掌握的C++面试题

C 有用的资源 C 有用的资源 以下资源包含了 C 有关的网站、书籍和文章。请使用它们来进一步学习 C 的知识。 C 有用的网站 C Programming Language Tutorials − C 编程语言教程。C Programming − 这本书涵盖了 C 语言编程、软件交互设计、C 语言的现实生活应用。C FAQ −…

chatgpt赋能python:Python中的遍历方法详解

Python中的遍历方法详解 在Python中&#xff0c;遍历是处理数据的常见操作。Python提供了多种遍历方法&#xff0c;本文将逐一介绍这些方法的特点、适用场景及使用方法。 for循环 for循环是Python中最常用的遍历方法之一&#xff0c;可以遍历任何可迭代对象。 # 遍历列表 f…

栈的运用——中缀表达式[Java实现]

⭐作者介绍&#xff1a;大二本科网络工程专业在读&#xff0c;持续学习Java&#xff0c;努力输出优质文章 ⭐作者主页&#xff1a;逐梦苍穹 ⭐所属专栏&#xff1a;数据结构。数据结构专栏主要是在讲解原理的基础上拿Java实现&#xff0c;有时候有C/C代码。 ⭐如果觉得文章写的…

C++【位图/布隆过滤器—海量数据处理】

文章目录 一、位图&#xff08;1&#xff09;位图概念介绍&#xff08;2&#xff09;简单模拟实现&#xff08;3&#xff09;位图应用 二、布隆过滤器&#xff08;1&#xff09;关于布隆过滤器概念及介绍&#xff08;2&#xff09;布隆过滤器的使用场景&#xff08;3&#xff0…

干翻Mybatis源码系列之第十一篇:Mybatis拦截器获取被拦截对象的方法和参数

给自己的每日一句 不从恶人的计谋&#xff0c;不站罪人的道路&#xff0c;不坐亵慢人的座位&#xff0c;惟喜爱耶和华的律法&#xff0c;昼夜思想&#xff0c;这人便为有福&#xff01;他要像一棵树栽在溪水旁&#xff0c;按时候结果子&#xff0c;叶子也不枯干。凡他所做的尽…

DJ4-1 网络层概述

目录 一、网络层提供的功能 二、路由和转发 三、数据平面和控制平面 四、网络层的服务模型 一、网络层提供的功能 网络层实现主机与主机之间的通信 从发送方主机传输报文段到接收方主机&#xff1a; 发送方主机封装报文段 (segments) 为数据报 (datagrams)接收方主机递交…

Linux常用命令——gcov命令

在线Linux命令查询工具 gcov 测试程序的代码覆盖率的工具 补充说明 gcov命令是一款测试程序的代码覆盖率的工具。 语法 gcov(选项)(参数)选项 -h&#xff1a;显示帮助信息&#xff1b; -v&#xff1a;显示版本信息&#xff1b; -a&#xff1a;输出所有的基本块的执行计数…