【链表经典算法OJ题】(1)

1.移除链表元素

单链表相关经典算法OJ题1:移除链表元素

. - 力扣(LeetCode). - 备战技术面试?力扣提供海量技术面试资源,帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。icon-default.png?t=N7T8https://leetcode.cn/problems/remove-linked-list-elements/

思路1:遍历原链表,将val节点释放掉

实现代码:

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


struct ListNode* removeElements(struct ListNode* head, int val)
{

  //这个循环可以解决两种情况
  //1.空链表
  //2.非空链表,而且第一个结点就是要删除的值,还会一直删除到不是val的结点
  //比如一个链表是这样的2->2->2->3,假设要删除的数字是2
  //走完下面这个循环后
  //head就指向3这个结点
  while (NULL != head && head->val == val)
  {
      head = head->next;
  }


  //
  struct ListNode* curr=head;
  struct ListNode* prev=NULL;
  while(curr!=NULL)
  {
      if(curr->val!=val)
      {
          prev=curr;
      }
      else
      {
          prev->next=curr->next;
      }
      curr=curr->next; 
  }
  return head;

思路2:找不为val的节点,尾插到新链表

实现代码:

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

typedef struct ListNode ListNode;
struct ListNode* removeElements(struct ListNode* head, int val)
{
    //创建一个空链表
    ListNode* newHead, * newTail;
    newHead = newTail = NULL;

    //遍历原链表
    ListNode* pcur = head;
    while (pcur)
    {
        //找值不为val的节点,尾插到新链表中
        if (pcur->val != val)
        {
            //链表为空
            if (newHead == NULL)
            {
                newHead = newTail = pcur;
            }
            else
            {
                //链表不为空
                newTail->next = pcur;
                newTail = newTail->next;
            }
        }
        pcur = pcur->next;
    }

    if (newTail)
    {
        newTail->next = NULL;
    }
    return newHead;
}

2.反转链表

单链表相关经典算法OJ题2: 反转链表
思路1:双指针法

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

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

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

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

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

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

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

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

实现代码:

// 双指针法:
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;
}

 3.合并两个有序链表

思路:

首先创建一个结点,然后比较两个链表的数值,将更小的那个结点并入刚创建的结点,以此类推,最后将还有剩余结点的链表介入新链表,注意节点为空等特殊情况的处理即可。

实现代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
 typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) 
{
    //如果list1和list2中有一个为空就直接返回另一个节点
    if(list1==NULL)
    {
        return list2;
    }
    if(list2==NULL)
    {
        return list1;
    }
    //定义l1,l2指针分别指向list1和list2的头节点
    ListNode*l1,*l2;
    ListNode*newHead,*newTail;
    //给新链表开辟一个哨兵位
    newHead=newTail=(ListNode*)malloc(sizeof(ListNode));
    l1=list1,l2=list2;
    while(l1&&l2)
    {
        if(l1->val<=l2->val)
        {
            newTail->next=l1;
            newTail=newTail->next;
            l1=l1->next;
        }
        else
        {
            newTail->next=l2;
            newTail=newTail->next;
            l2=l2->next;
        }
    }
    if(l1)
    {
        newTail->next=l1;

    }
    if(l2)
    {
        newTail->next=l2;
    }
    //新链表的第一个节点是头结点为无效数据,因此返回头结点的next
    return newHead->next;
}

本篇文章只介绍了题目的部分解法。如果本篇有补充的地方,欢迎私信我或在评论区指出,期待与你们共同进步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值