【编织时空三:探究顺序表与链表的数据之旅】(上)

简介: 【编织时空三:探究顺序表与链表的数据之旅】

本章重点


  • 链表OJ题


1. 删除链表中等于给定值 val 的所有结点。 OJ链接


思路一:删除头结点时另做考虑(由于头结点没有前一个结点)

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


思路二:添加一个虚拟头结点,删除头结点就不用另做考虑

struct ListNode* removeElements(struct ListNode* head, int val)
{
    struct ListNode* cur = head;
    struct ListNode* newhead = NULL;
    struct ListNode* tail = NULL;
    while (cur != NULL)
    {
        if (cur->val == val)
        {
            struct ListNode* del = cur;
            cur = cur->next;
            free(del);
        }
        else
        {
            //尾插
            if (tail == NULL)
            {
                newhead = tail = cur;
            }
            else
            {
                tail->next = cur;
                tail = tail->next;
            }
            cur = cur->next;
        }
    }
    if (tail)//如果最后一个数是要删除的,tail就需要置空
        tail->next = NULL;
    return newhead;
}


2. 反转一个单链表。OJ链接


思路:通过三个指针的操作,每次将当前节点反转并向前移动

struct ListNode* reverseList(struct ListNode* head) 
{ 
    assert(head);    
    struct ListNode* n1, * n2, * n3;
  n1 = NULL;
  n2 = head;
  n3 = n2->next;
  while (n2)
  {
    //翻转
    n2->next = n1;
    //交换
    n1 = n2;
    n2 = n3;
    //记录位置
        if(n2 != NULL)
        n3 = n3->next;
  }
  return n1;
}


思路:头插法

struct ListNode* reverseList(struct ListNode* head) 
{
  struct ListNode* cur = head;
  struct ListNode* newhead = NULL;
  while (cur)
  {
    //保存cur下一个结点的位置
    struct ListNode* next = cur->next;
    //头插
    next = newhead;
    newhead = cur;
    //更新
    cur = next;
  }
  return newhead;
}


3. 给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则 返回第二个中间结点。OJ链接


思路:快慢指针的前进方向相同,且它们步伐的「差」是恒定的,使用两个指针变量,刚开始都位于链表的第 1 个结点,一个永远一次只走 1 步,一个永远一次只走 2 步,一个在前,一个在后,同时走。这样当快指针走完的时候,慢指针就来到了链表的中间位置。

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


4. 输入一个链表,输出该链表中倒数第k个结点。OJ链接


首先让快指针先行k步,然后让快慢指针每次同行一步,直到快指针指向空节点,慢指针就是倒数第K个节点。

struct ListNode* FindKthToTail(struct ListNode* pListHead, int k)
{
  struct ListNode* fast = pListHead;
  struct ListNode* slow = pListHead;
  while (k--)//走k步
  {
    //链表没有k步长,那么此时倒数就是空
    if (fast == NULL)
      return NULL;
    fast = fast->next;
  }
  while (fast)
  {
    slow = slow->next;
    fast = fast->next;
  }
  return slow;
}


5. 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有结点组成的。OJ链接


思路一:我们可以用迭代的方法来实现上述算法。当 l1 和 l2 都不是空链表时,判断 l1 和 l2 哪一个链表的头节点的值更小,将较小值的节点添加到结果里,当一个节点被添加到结果里之后,将对应链表中的节点向后移一位。

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) 
{
  if (list1 == NULL)
    return list2;
  if (list2 == NULL)
    return list1;
  struct ListNode* newhead = NULL;
  struct ListNode* tail = NULL;
  while (list1 && list2)
  {
    //小值给到新链表上
    if (list1->val < list2->val)
    {
      if (tail == NULL)
      {
        newhead = tail = list1;
      }
      else
      {
        tail->next = list1;
        tail = tail->next;
      }
      list1 = list1->next;
    }
    else
    {
      if (tail == NULL)
      {
        newhead = tail = list2;
      }
      else
      {
        tail->next = list2;
        tail = tail->next;
      }
      list2 = list2->next;
    }
  }
  if (list1)
    tail->next = list1;
  if (list2)
    tail->next = list2;
  return newhead;
}


【编织时空三:探究顺序表与链表的数据之旅】(下):https://developer.aliyun.com/article/1424879

相关文章
|
1月前
|
存储
顺序表和链表(2)
【10月更文挑战第23天】
顺序表和链表(2)
|
1月前
|
存储 算法 数据管理
顺序表和链表(1)
【10月更文挑战第22天】
|
2月前
|
存储 安全 Java
【用Java学习数据结构系列】探索顺序表和链表的无尽秘密(附带练习唔)pro
【用Java学习数据结构系列】探索顺序表和链表的无尽秘密(附带练习唔)pro
28 3
|
6月前
|
存储 缓存 算法
数据结构和算法学习记录——总结顺序表和链表(双向带头循环链表)的优缺点、CPU高速缓存命中率
数据结构和算法学习记录——总结顺序表和链表(双向带头循环链表)的优缺点、CPU高速缓存命中率
56 0
|
4月前
|
存储 算法
【初阶数据结构篇】顺序表和链表算法题
此题可以先找到中间节点,然后把后半部分逆置,最近前后两部分一一比对,如果节点的值全部相同,则即为回文。
39 0
|
4月前
|
存储 缓存
【数据结构】——顺序表与链表
【数据结构】——顺序表与链表
|
6月前
|
存储 索引
顺序表和链表
通过以上示例,我们可以看到顺序表和链表在实际应用中如何操作。顺序表适合于需要频繁读取数据的场景,而链表则更适用于频繁修改数据的情况。在选择使用哪种数据结构时,应考虑到实际应用的需求和上下文环境。
43 2
|
6月前
|
存储 缓存
【海贼王的数据航海】链表—双向链表
【海贼王的数据航海】链表—双向链表
31 0
|
6月前
|
存储
【海贼王的数据航海】链表—单链表
【海贼王的数据航海】链表—单链表
37 0
|
6月前
|
存储 算法
数据结构和算法学习记录——线性表之单链表(上)-初始单链表及其尾插函数(顺序表缺陷、单链表优点、链表打印)
数据结构和算法学习记录——线性表之单链表(上)-初始单链表及其尾插函数(顺序表缺陷、单链表优点、链表打印)
45 0