数据结构初阶--链表OJ

前言

本篇文章将对部分单链表的OJ题进行讲解

移除链表元素

我们先来看题

思路分析

我们可以采用双指针的方法来解决这个问题,我们用cur指针来遍历链表,找到待删除的元素,并用一个prev指针来保存上一个节点,使该结点的next指向cur结点的next(即待删除元素下一个节点的地址),如果没找到,就将prev指向cur,cur指向cur->next进行迭代。
注意,我们还要考虑第一个节点的val就是待删除元素的情况,这时候的头节点就应该指向下一个节点。

代码实现

代码的实现如下

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


struct ListNode* removeElements(struct ListNode* head, int val){
        struct ListNode*prev=NULL,*cur=head;
    while(cur)
    {
        if(cur->val==val)
        {
            if(cur==head)
            {
                head=cur->next;
                cur=head;
            }
            else
            {
                prev->next=cur->next;
                free(cur);
                cur=prev->next;
            }
        }
        else
        {
            prev=cur;
            cur=cur->next;
        }
    }
    return head;
}

链表的中间节点

先来看题目描述

思路分析

我们常规的思路是先用cur遍历一遍链表,并保存其长度,然后再遍历长度的一半次,返回最后的节点位置,这个方法可行,但是需要遍历两次链表,有没有方法能只遍历一遍链表就能找出中间节点呢?
当然可以,这里采用的就是快慢指针的方法,慢指针每次走一步,快指针每次走两步当快指针的下一个节点为空时停止遍历,此时慢指针指向的就是中间节点

代码实现

代码实现如下

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


struct ListNode* middleNode(struct ListNode* head){
    struct ListNode* slow=head;
    struct ListNode* fast=head;
    while(fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;
        if(fast==NULL)
        break;
    }
    return slow;

}

反转链表

思路分析

这道题的思路和我们以前做过的<font color=orange.数组元素逆置十分相像,我们知道,要想交换两个位置的值,需要一个中间变量才能实现,所以本题我们也创建一个新的节点来临时保存其中的一个节点,防止出现找不到节点的情况,然后再将节点尾插的即可

代码实现

代码实现如下

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


struct ListNode* reverseList(struct ListNode* head){
    struct ListNode* cur=head;
    struct ListNode* pre=NULL;
    while(cur)
    {
        struct ListNode* tmp=cur->next;
        cur->next=pre;
        pre=cur;
        cur=tmp;
    }

    return pre;

}

链表分割

先来看题目描述

思路分析

1,我们令cur=pHead
2,让cur遍历链表,再开辟两个新结点lessHead和greaterHead,把链表分为两部分,第一部分是小于x的结点放在lessHead->next里,大于x的结点放在greaterHead->next里
3,当cur走到NULL时,让lessTail->next=greaterHead->next,这样就把两个链表按照原来的相对顺序连接起来
4,返回lessHead->next.

代码实现

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};*/
class Partition {
public:
    ListNode* partition(ListNode* pHead, int x) {
        // write code here
        struct ListNode* greatHead, *greattail, *lessHead, *lesstail, *cur;
        greatHead = greattail = (struct ListNode*)malloc(sizeof(struct ListNode));
        lessHead = lesstail = (struct ListNode*)malloc(sizeof(struct ListNode));
        cur = pHead;
        while(cur)
        {
            if(cur->val < x)
            {
                lesstail->next = cur;  
                lesstail = cur;   
                cur = cur->next; 
            }
            else
            {
                greattail->next = cur;
                greattail = cur;
                cur = cur->next;
            }
        }
         
        lesstail->next = greatHead->next;  
        greattail->next = NULL;   
         
        return lessHead->next;
    }
};

合并两个有序链表

还是先来看题目描述

思路分析

  1. 我们首先考虑其中一个链表为空的情形,这样就只用返回另一个头节点即可。
  2. 然后我们malloc一个节点pS,作为哨兵位,这样就可以避免区分第一个节点是否为空的问题,然后分别遍历list1和list2,用temp指针来接收节点并往后走。
  3. 当list1或list2有一个为空时停止遍历然后判断另一个链表是否为空,若不为空,则将temp->next指向不为空的链表的头结点进行链接。
  4. 最后返回pS->next.

代码实现

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

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
    if(list1==NULL) {
        return list2;
    } else if(list2==NULL) {
        return list1;
    }

    struct ListNode* pS=(struct ListNode*)malloc(sizeof(struct ListNode));
    struct ListNode* temp=pS;
    while(list1!=NULL && list2!=NULL) {
        if(list1->val<=list2->val) {
            temp->next=list1;
            list1=list1->next;
        } else {
            temp->next=list2;
            list2=list2->next;
        }
        temp=temp->next;
    }

    if(list1!=NULL) {
        temp->next=list1;
    } 
    if(list2!=NULL) {
        temp->next=list2;
    }

    return pS->next;
}

以上就是本篇文章的全部内容,如有出入,欢迎指正。

  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

偷吃橙子的喵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值