盘点那些必问的数据结构算法题之链表

本文详细介绍了链表的基础概念、基本操作,以及一系列面试常考的链表问题,包括链表逆序、复制、合并、相交判断、环的存在性检测、模拟加法、有序循环链表插入结点和输出倒数第K个结点。通过这些题目,深入理解链表操作的技巧和算法思路。

0 概述

链表作为一种基础的数据结构,在很多地方会用到。如在Linux内核代码,redis源码,python源码中都有使用。除了单向链表,还有双向链表,本文主要关注单向链表(含部分循环链表题目,会在题目中注明,其他情况都是讨论简单的单向链表)。双向链表在redis中有很好的实现,也在我的仓库中拷贝了一份用于测试用,本文的相关代码在 这里。

https://github.com/shishujuan/data-structure-algorithms

1 定义

先定义一个单向链表结构,如下,定义了链表结点和链表两个结构体。这里我没有多定义一个链表的结构体,保存头指针,尾指针,链表长度等信息,目的也是为了多练习下指针的操作。

// aslist.h

// 链表结点定义
typedef struct ListNode {
    struct ListNode *next;
    int value;
} listNode;

2 基本操作

在上一节的链表定义基础上,我们完成几个基本操作函数,包括链表初始化,链表中添加结点,链表中删除结点等。

/**
 * 创建链表结点
 */
ListNode *listNewNode(int value)
{
    ListNode *node;
    if (!(node = malloc(sizeof(ListNode))))
        return NULL;

    node->value = value;
    node->next = NULL;
    return node;
}

/**
 * 头插法插入结点。
 */
ListNode *listAddNodeHead(ListNode *head, int value)
{
    ListNode *node;
    if (!(node = listNewNode(value)))
        return NULL;

    if (head) 
        node->next = head;

    head = node;
    return head;
}

/**
 * 尾插法插入值为value的结点。
 */
ListNode *listAddNodeTail(ListNode *head, int value)
{
    ListNode *node;
    if (!(node = listNewNode(value)))
        return NULL;

    return listAddNodeTailWithNode(head, node);
}

/**
 * 尾插法插入结点。
 */
ListNode *listAddNodeTailWithNode(ListNode *head, ListNode *node)
{
    if (!head) {
        head = node;
    } else {
        ListNode *current = head;
        while (current->next) {
            current = current->next;
        } 
        current->next = node;
    }
    return head;
}

/**
 * 从链表删除值为value的结点。
 */
ListNode *listDelNode(ListNode *head, int value)
{
    ListNode *current=head, *prev=NULL;

    while (current) {
        if (current->value == value) {
            if (current == head)
                head = head->next;

            if (prev)
                prev->next = current->next;

            free(current);
            break;
        }

        prev = current;
        current = current->next;
    }
    return head;
}

/**
 * 链表遍历。
 */
void listTraverse(ListNode *head)
{
    ListNode *current = head;
    while (current) {
        printf("%d", current->value);
        printf("->");
        current = current->next;
        if (current == head) // 处理首尾循环链表情况
            break;
    }

    printf("NULL\n");
}

/**
 * 使用数组初始化一个链表,共len个元素。
 */
ListNode *listCreate(int a[], int len)
{
    ListNode *head = NULL;
    int i;
    for (i = 0; i < len; i++) {
        if (!(head = listAddNodeTail(head, a[i])))
            return NULL;
   &nb
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值