链表PART2

目录

链表的分类

链表说明:

1. 链表的单向或双向

2. 链表的带头或不带头

3. 链表的循环和不循环

单链表例题

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

解题思路:

示例代码:

2. 单链表相关算法OJ题2:链表的中间结点

解题思路:

示例代码:

3. 单链表相关算法OJ题3:反转链表

​编辑​编辑

 解题思路:

示例代码:

4. 单链表相关算法OJ题4:合并两个有序链表

解题思路:

示例代码:

5. 单链表相关算法OJ题5:分割链表

解题思路:

示例代码:


链表的分类

前一篇讲的单链表:

struct SListNode
{
	int data;       //节点数据
	struct SListNode* next;   //指针变量用于保存下一个节点的数据
};

SList 即 single linked list,单链表全称是不带头单向不循环链表

而链表的结构多样,以下一共有8种(2*2*2)链表结构。

链表说明:

1. 链表的单向或双向

单线链表可以通过前驱节点找到后继节点,但是无法通过后继节点找到前驱节点;

双向链表不但可以通过前驱节点找到后继节点,还可以通过后继节点找到前驱节点。

2. 链表的带头或不带头

注意:在上一篇单链表中的提到的“头节点”的“头”和“带头链表”的“头”不是一个概念。

单链表中的“头节点”指的是 第一个有效的节点;

“带头链表”的“头”指的是 无效的节点,称为哨兵位,它不保存任何有效的数据。 

3. 链表的循环和不循环

循环链表的最后一个节点的next指向的是第一个节点,成为一个环。

人们常用的两种链表分别为:

单链表(不带头单向不循环链表)双向链表(带头双向循环链表)

单链表例题

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

解题思路:

思路一:先遍历链表,遇到 val 就删除。

 但是,执行删除操作修改指针的指向比较麻烦,所以再想想其他方法。

思路二:定义一个新链表,遍历原链表,找不为 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(NewTail == NULL)
            {
                NewHead = NewTail = pcur;
            }
            //链表不为空
            else
            {
                NewTail->next = pcur;
                NewTail = NewTail->next;
            }
        }
        //刚好是val,不插入,pcur向后找
        pcur = pcur->next;
    }
    if(NewTail)
    {
        NewTail->next = NULL;
    }
    return NewHead;
}

2. 单链表相关算法OJ题2:链表的中间结点

解题思路:

思路一:遍历链表,统计链表节点的个数,通过除以2找到中间节点。

这个思路需要两层for循环:for(统计链表个数) 和 for(根据除以2找到中间节点)

思路二:使用快慢指针。让 show 指针每次走一步,让 fast 指针每次走两步。

当 fast 的 next 为空时(或者 fast 为空),show 指针刚好指向的就是中间节点。

示例代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
 typedef struct ListNode ListNode;
struct ListNode* middleNode(struct ListNode* head) {
    ListNode *show, *fast;
    show = fast = head;

    while(fast && fast->next)
    {
        //快慢指针
        show = show->next;
        fast = fast->next->next;

    }
    return show;

}

 

3. 单链表相关算法OJ题3:反转链表

 解题思路:

思路一:创建新链表,遍历原链表的节点,将其插入新链表中。

思路二:创建三个指针,分别记录前驱节点、当前节点、后继节点。改变原链表指针指向。

              让n2的next反向指向n1,n1走到n2,n2走到n3,n3 = n3->next……

示例代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
 typedef struct ListNode ListNode;
struct ListNode* reverseList(struct ListNode* head) {
    //空链表
    if(head == NULL)
    {
        return head;
    }
    //创建3个指针
    ListNode* n1, *n2, *n3;
    n1 = NULL;
    n2 = head;
    n3 = head->next;
    //遍历原链表,修改指针指向
    ListNode* pcur = head;
    while(n2)
    {
        //修改n2指向
        n2->next = n1;
        //修改指针位置
        n1 = n2;
        n2 = n3;
        if(n3)
        {
            n3 = n3->next;
        }
    }
    return n1;
}

4. 单链表相关算法OJ题4:合并两个有序链表

解题思路:

创建新链表,两个原链表分别创建一个指针用于比较大小,小的一方插入新链表。

示例代码:

/**
 * 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) {
    //链表为空
    if(list1 == NULL)
    {
        return list2;
    }
    if(list2 ==NULL)
    {
        return list1;
    }
    ListNode* l1, *l2;
    l1 = list1;
    l2 = list2;
    ListNode* NewHead,*NewTail;
    NewHead = NewTail = NULL;

    while(l1 && l2)
    {
        if(l1->val < l2->val)
        {
            //把l1插入新链表
            if(NewHead ==NULL)
            {
                NewHead = NewTail = l1;
            }
            else
            {
                NewTail->next = l1;
                NewTail = NewTail->next;
            }
            l1 = l1->next;
        }
        else
        {
            //把l2插入新链表
            if(NewHead == NULL)
            {
                NewHead = NewTail = l2;
            }
            else
            {
                NewTail->next = l2;
                NewTail = NewTail->next;
            }
            l2 = l2->next;
        }
    }
    //l2到头l1还没
    if(l1)
    {
        NewTail->next = l1;
    }
    //l1到头l2还没
    if(l2)
    {
        NewTail->next = l2;
    }
    return NewHead;
}

优化重复代码后(增加了哨兵位):

/**
 * 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)
{
    if(list1 == NULL)
    {
        return list2;
    }
    if(list2 == NULL)
    {
        return list1;
    }
    ListNode *l1, *l2;
    l1 = list1;
    l2 = list2;

    ListNode *NewHead, *NewTail;
    NewHead = NewTail = (ListNode*)malloc(sizeof(ListNode));

    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;
        }
    }
    // l2到头l1还没
    if (l1) {
        NewTail->next = l1;
    }
    // l1到头l2还没
    if (l2) {
        NewTail->next = l2;
    }
    ListNode* ret = NewHead->next;
    free(NewHead);
    return ret;
}

 

5. 单链表相关算法OJ题5:分割链表

解题思路:

定义两个新链表,一个存放大于等于 x 的节点,一个存放小于 x 的节点。遍历原链表节点将其放入新链表里,最后将两个链表相连。

示例代码:

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

typedef struct ListNode ListNode;
struct ListNode* partition(struct ListNode* head, int x)
{
    if(head == NULL)
    {
        return head;
    }
    //创建带头的大小链表
    ListNode* lessHead, *lessTail;
    ListNode* greaterHead, *greaterTail;
    lessHead = lessTail = (ListNode*)malloc(sizeof(ListNode));
    greaterHead = greaterTail = (ListNode*)malloc(sizeof(ListNode));
    
    //遍历原链表,处理节点
    ListNode* pcur = head;
    while(pcur)
    {
        if(pcur->val < x)
        {
            //放到小链表中
            lessTail->next = pcur;
            lessTail = lessTail->next;
        }
        else
        {
            //放到大链表中
            greaterTail->next = pcur;
            greaterTail = greaterTail->next;
        }
        pcur = pcur->next;
    }
    greaterTail->next = NULL;
    //链表连接
    lessTail->next = greaterHead->next;
    ListNode* ret = lessHead->next;
    free(greaterHead);
    free(lessHead);
    return ret;
}

  • 54
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

YMLT花岗岩

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

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

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

打赏作者

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

抵扣说明:

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

余额充值