zoukankan      html  css  js  c++  java
  • 面试-反转链表

    面试-反转链表

    面试题目

    经典算法题目 : 反转单链表 reverse list

    对于一个普通的单链表,可以定义成结构体形式:

    // 定义链表节点
    struct ListNode
    {
      int val;
      ListNode * next;
    }

    请写一个函数实现单链表的翻转

    题目解析

    一般来说,单链表的反转有递归和非递归的方式来进行实现, 此处的反转实现 参考反转链表图示 其中递归方式的实现比较难以理解, 进攻参考

    递归方式
    // 递归方式
    ListNode * ReverseList_re(ListNode * head)
    {
        // 如果空链表或者 单节点链表
        if(head ==nullptr || head->next == nullptr)
            return head;
    
        // 依次进行每个节点的执行
        ListNode * new_head = ReverseList_re(head->next);
    
        // 对于每一个节点 反转前后实现
        head->next->next = head;
        head->next = nullptr;
    
        return new_head;
    }
    非递归方式
    1.  
    2. // ref:[链表反转图文讲解](https://blog.csdn.net/FX677588/article/details/72357389) 
    3. // 非递归方式 
    4. ListNode * ReverseList(ListNode *head) 
    5. { 
    6. // 如果空链表或者 单节点链表 
    7. if(head == nullptr || head->next == nullptr) 
    8. return head; 
    9.  
    10. // 新建两个节点 P用来遍历head, new_head 为新链表的头 
    11. ListNode *p = head, *new_head = nullptr; 
    12.  
    13. while(p != nullptr) 
    14. { 
    15. ListNode * tmp = p->next; // 存储当前节点的指针位置 
    16. p->next = new_head; // 将当前节点指向新节点的头 
    17. new_head = p; // 新链表 移动头 
    18. p = tmp; // 旧链表指针移动 
    19. } 
    20.  
    21. // 返回新的节点值 
    22. return new_head; 
    23. } 
    24.  
    25. // 不返回操作 非递归 反转链表 
    26. void ReverseList2(ListNode * &head) 
    27. { 
    28. // 如果空链表或者 单节点链表 
    29. if(head == nullptr || head->next == nullptr) 
    30. return ; 
    31.  
    32. // 新建两个节点 P用来遍历head, new_head 为新链表的头 
    33. ListNode *p = head, *new_head = nullptr; 
    34.  
    35. while(p != nullptr) 
    36. { 
    37. ListNode * tmp = p->next; // 存储当前节点的指针位置 
    38. p->next = new_head; // 将当前节点指向新节点的头 
    39. new_head = p; // 新链表 移动头 
    40. p = tmp; // 旧链表指针移动 
    41. } 
    42.  
    43. // 复用 head 指针 
    44. head = new_head; 
    45. } 
    46.  

    附加内容

    测试工程 实现

    // 链表操作类的 测试
    #include <iostream>
    
    using namespace std;
    
    // 定义链表节点 值和指针
    struct ListNode
    {
        int val;
        ListNode *next;
    };
    
    // 定义链表的 增 删 查 改
    // CRUD
    
    // 创建链表 // 根据首指针 创建首指针节点
    void CreateHead(ListNode *head, int data)
    {
    
    }
    
    // 在链表尾头部添加新节点
    void AddNode(ListNode * & head,int data)
    {
        // 创建 新节点 //申请空间
        ListNode *p = (ListNode*) malloc(sizeof(ListNode));
        p->val = data;
        p->next = nullptr;
    
        // 如果是一个空链表 直接赋值到head 然后返回
    
        if(head == nullptr)
        {
            head = p;
            return ;
        }
    
        // 指向新节点 返回新节点
        p->next = head;
        head = p;
    }
    
    // 删除节点
    
    // 查找节点
    
    // 更新节点值
    
    // 打印List 所有节点值
    void PrintList(ListNode *head)
    {
        // 从某个节点开始 打印所有节点的值
        ListNode *p = head; // 临时节点 便于输出 避免 改变 head 值
        while(p != nullptr)
        {
            // cout<<(long)p%65536<<":";        // 输出指针的一个 数字表示
            cout<<p->val<<"->";
            p = p->next;
        }
        cout<<"NULL"<<endl;
    }
    
    
    // 反转链表
    // ref:[链表反转图文讲解](https://blog.csdn.net/FX677588/article/details/72357389)
    // 非递归方式
    ListNode * ReverseList(ListNode *head)
    {
        // 如果空链表或者 单节点链表
        if(head == nullptr || head->next == nullptr)
            return head;
    
        // 新建两个节点 P用来遍历head, new_head 为新链表的头
        ListNode *p = head, *new_head = nullptr;
    
        while(p != nullptr)
        {
            ListNode * tmp = p->next;   // 存储当前节点的指针位置
            p->next = new_head;         // 将当前节点指向新节点的头
            new_head = p;               // 新链表 移动头
            p = tmp;                    // 旧链表指针移动
        }
    
        // 返回新的节点值
        return new_head;
    }
    
    // 不返回操作  非递归 反转链表
    void ReverseList2(ListNode * &head)
    {
        // 如果空链表或者 单节点链表
        if(head == nullptr || head->next == nullptr)
            return ;
    
        // 新建两个节点 P用来遍历head, new_head 为新链表的头
        ListNode *p = head, *new_head = nullptr;
    
        while(p != nullptr)
        {
            ListNode * tmp = p->next;   // 存储当前节点的指针位置
            p->next = new_head;         // 将当前节点指向新节点的头
            new_head = p;               // 新链表 移动头
            p = tmp;                    // 旧链表指针移动
        }
    
        // 复用 head  指针
        head = new_head;
    }
    
    // 递归方式
    ListNode * ReverseList_re(ListNode * head)
    {
        // 如果空链表或者 单节点链表
        if(head ==nullptr || head->next == nullptr)
            return head;
    
        // 依次进行每个节点的执行
        ListNode * new_head = ReverseList_re(head->next);
    
        // 对于每一个节点 反转前后实现
        head->next->next = head;
        head->next = nullptr;
    
        return new_head;
    }
    
    
    // 主函数 测试 demo 
    #define LENGTH 20 
    int main(void)
    {
        ListNode *head  = nullptr;
    
        // 生成随机链表
        for(int i=0;i<LENGTH;++i)
            AddNode(head,rand()%LENGTH);
        PrintList(head);
    
        // 反转链表 并输出
        head = ReverseList(head);
        PrintList(head);
    
        // 反转链表 并输出
        ReverseList2(head);
        PrintList(head);
    
        // 反转链表 并输出 递归实现
        head = ReverseList_re(head);
        PrintList(head);
    
        // system("pause");
        return 0;
    }
    
    
  • 相关阅读:
    【python cookbook】找出序列中出现次数最多的元素
    2018/1/21 Netty通过解码处理器和编码处理器来发送接收POJO,Zookeeper深入学习
    读《风雨20年》小感
    两个知识点的回顾(const指针和动态链接库函数dlopen)
    小试牛刀
    chmod,chown和chgrp的区别
    node.js中使用node-schedule实现定时任务
    在 Node.js 上调用 WCF Web 服务
    nodejs发起HTTPS请求并获取数据
    openstack 之~云计算介绍
  • 原文地址:https://www.cnblogs.com/hugochen1024/p/12570660.html
Copyright © 2011-2022 走看看