数据结构--链表OJ习题1

1 移除链表结构

1.1 题目介绍

删除链表中等于给定值 val 的所有节点。

示例:

输入: 1->2->6->3->4->5->6, val = 6
输出: 1->2->3->4->5

题目来源:https://leetcode-cn.com/problems/remove-linked-list-elements/description/

1.2 题目分析

1.2.1 基本思路

  • 步骤一:定义一个指针变量cur用来遍历整个链表,指针变量prev表示链表中当前节点的上一个节点;
  • 步骤二:判断cur->data == val是否成立,不成立则prev = cur ;cur = cur->next ;
  • 步骤三:若不成立,则删除cur指向的节点 。

1.2.2 关键变量

  • cur 指向当前访问的节点
  • prev 表示链表中当前节点的上一个节点

1.3 程序代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* removeElements(struct ListNode* head, int val){
    struct ListNode* cur , *prev;
    cur = head ;
    prev = NULL;
    while(cur){
        //数据等于val,则删除该节点
        if(cur->val == val){
            struct ListNode* next = cur->next ;
            if(prev == NULL){
                head = next ;
            }else{
                prev->next = next ;
            }
            free(cur);
            cur = next ;
        }else{
            prev = cur ;
            cur = cur->next ;
        }
    }
    return head ;
}

1.4 代码运行

在这里插入图片描述

2 反转链表

2.1 题目介绍

反转一个单链表。

示例:

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

题目来源:https://leetcode-cn.com/problems/reverse-linked-list/submissions/

2.2 题目分析

2.2.1 基本思路

方法一:

  • 步骤一:创建一个链表head2;
  • 步骤二:将原有链表的首个节点取下,并头插入head2链表中;
  • 步骤三:不断重复步骤二,直至原有链表为空。

方法二:

  • 步骤一:使用三个指针变量n1、n2、n3来辅助链表的反转;
  • 步骤二:使n2->next = n1;
  • 步骤三:使n1 = n2 ; n2 = n3 ; n3 = n3->next;
  • 步骤四:不断重复上述操作,直至n2的值为空;
  • 步骤五:使head = n1

2.2.2 关键变量

  • n2表示需要反转的节点
  • n1表示需要反转节点应指向的节点
  • n3表示需要反转的下一个节点

2.3 程序代码

方法一:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* reverseList(struct ListNode* head){
    struct ListNode* head2 = NULL;
    //当原有节点不为空时进行循环
    while(head != NULL){
        //从原有节点上取出第一个节点
        struct ListNode* cur = head ;
        head = head->next ;

        //将取出的节点头插入head2链表中
        cur->next = head2;
        head2 = cur ;
    }
    return head2 ;
}

方法二:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* reverseList(struct ListNode* head){
    if(head == NULL || head->next == NULL)
        return head ;
    //定义三个辅助指针变量并进行初始赋值
    struct ListNode* n1 , *n2 , *n3 ;
    n1 = head ;
    n2 = head->next ;
    n3 = n2->next ;
    n1->next = NULL;

    //当n2不为空时进行循环
    while(n2){
        //将n2节点指向反转
        n2->next = n1 ;
        //将三个辅助指针变量向后移动
        n1 = n2 ;
        n2 = n3 ;
        if(n3 != NULL){
            n3 = n3->next ;
        }
    }
    head = n1 ;
    return head ;
}

2.4 代码运行

方法一:
在这里插入图片描述
方法二:
在这里插入图片描述

3 链表的中间节点

3.1 题目介绍

给定一个头结点为 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。
示例 :

输入:[1,2,3,4,5]
输出:此列表中的结点 3 (序列化形式:[3,4,5])
返回的结点值为 3 。 (测评系统对该结点序列化表述是 [3,4,5])。
注意,我们返回了一个 ListNode 类型的对象 ans,这样:
ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL.

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/middle-of-the-linked-list

3.2 题目分析

3.2.1 基本思路

方法一:

  • 步骤一:遍历链表,统计链表节点的个数size;
  • 步骤二:找到第size/2+1个节点,该节点即为中间节点。

方法二:

  • 步骤一:设置快慢指针fast = slow = head
  • 步骤二:fast指针每次向前推进2个节点,slow指针每次向前推进1个节点;
  • 步骤三:当fast指针指向最后一个节点或fast指针为空时,slow指针指向链表的中间节点。

3.2.2 关键变量

  • fast表示快指针
  • slow表示慢指针

3.3 程序代码

方法一:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* middleNode(struct ListNode* head){
    if(head == NULL )
        return head ;
    int size = 0 ;
    struct ListNode* cur = head ;
    //统计链表节点数
    while(cur){
        size++;
        cur = cur->next ;
    }
    //找到第len/2+1个节点
    int middle = size/2+1;
    cur = head ;
    while(--middle){
        cur = cur->next ;
    }
    return cur;
}

方法二:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* middleNode(struct ListNode* head){
    //设置快慢指针
    struct ListNode* fast , *slow ;
    fast = slow = head ;
    //当快指针为最后一个节点或者为空是结束循环
    while(fast && fast->next){
        //快指针步长为2,慢指针步长为1
        fast = fast->next->next;
        slow = slow->next;
    }
    return slow ;
}

3.4 代码运行

方法一:
在这里插入图片描述
方法二:
在这里插入图片描述

4 倒数第k个节点

4.1 题目介绍

输入一个链表,输出该链表中倒数第k个节点。
示例

输入:1,{1,2,3,4,5}
返回值:{5}

题目链接:剑指offer找到倒数第k个节点

4.2 题目分析

4.2.1 基本思路

方法一:
步骤一:遍历链表,统计链表结点的个数size;
步骤二:返回第size-k个节点的下一个节点。
方法二:
步骤一:设置快慢指针fast = slow = head
步骤二:先让快指针先走k步;
步骤三:快慢指针同时向后移动,当快指针为空时,慢指针指向返回结点。

4.2.2 关键变量

  • fast表示快指针
  • slow表示慢指针

4.3 程序代码

方法一:

/**
 * struct ListNode {
 *  int val;
 *  struct ListNode *next;
 * };
 */
 
/**
 *
 * @param pListHead ListNode类
 * @param k int整型
 * @return ListNode类
 */
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
    // write code here
    int size = 0;
    struct ListNode* cur = pListHead;
    while(cur){
        size++;
        cur = cur->next ;
    }
    cur = pListHead ;
    int ret = size - k ;
    while(ret--&& cur){
        cur = cur->next ;
    }
    return cur ;
}

方法二:

/**
 * struct ListNode {
 *	int val;
 *	struct ListNode *next;
 * };
 */

/**
 * 
 * @param pListHead ListNode类 
 * @param k int整型 
 * @return ListNode类
 */
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
    // write code here
    //设置快慢指针`fast = slow = head`
    struct ListNode* fast , *slow ;
    fast = slow = pListHead ;
    //先让快指针先走k步
    while(k && fast){
        k--;
        fast = fast->next ;
    }
    if(k > 0)
        return NULL;
    //快慢指针同时向后移动,当快指针为空时,慢指针指向返回结点
    while(fast){
        fast = fast->next ;
        slow = slow->next ;
    }
    return slow ;
}

4.4 代码运行

方法一:
在这里插入图片描述
方法二:
在这里插入图片描述

5 有序链表的合并

5.1 题目介绍

将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:

输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/merge-two-sorted-lists

5.2 题目分析

5.2.1 基本思路

方法一:
申请一个链表,将两个链表中元素按升序赋给新链表节点的val中,销毁两个链表并返回新链表。
方法二:
步骤一:申请一个新的表头,并设置指向当前节点的指针cur = NULL
步骤二:设置指向两个有序链表当前节点的指针cur1、cur2;
步骤三:比较cur1->valcur2->val的值,将值较小的节点插入新链表中,即if(cur) cur->next = cur1(或cur2);
步骤四:当cur1 != NULL && cur2 != NULL 时,不断重复步骤三;
步骤五:将剩余的链表元素直接插入新的链表中;
步骤六:返回新的链表。
方法一的具体实现与合并两个数组的方法类似,故这里不详细讲述。

5.2.2 关键变量

  • cur指向新链表的当前节点
  • cur1指向链表l1的当前节点
  • cur2指向链表l2的当前节点

5.3 程序代码2

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
    //创建新的链表
    struct ListNode* newList , * cur , *cur1 , *cur2 ;
    cur1 = l1 ;
    cur2 = l2 ;

    //创建头节点
    struct ListNode* head =(struct ListNode*)malloc(sizeof(struct ListNode));
    head->next = NULL;
    newList = cur = head ;

    //将较小者插入新链表中
    while(cur1 && cur2){
        struct ListNode* inst;
        if(cur1->val <= cur2->val){
            inst = cur1 ;
            cur1 = cur1->next ;
        }else{
            inst = cur2 ;
            cur2 = cur2->next ;
        }

        cur->next = inst ;
        cur = inst ;
        
    }

    //将剩余元素加入新链表
    if(cur1){
        cur->next = cur1;
    }
    if(cur2){
        cur->next = cur2;
    }
 
    newList = head->next;
    free(head);
    return newList ;
}

5.4 代码运行

在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值