链表-两数相加/环形链表

1、两数相加

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

// 思路:获取长度,长度较短的补0.依次相加然后进位
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode *head = new ListNode(0);
        ListNode *newList = head;
        long i = 0;
        while(l1 != NULL|| l2 != NULL || i != 0){
            if(l1 != NULL) {
                i += l1->val;
                l1 = l1 -> next;              
            }
            if(l2 != NULL) {
                i += l2->val;
                l2 = l2 -> next;
            }
            ListNode* node = new ListNode();
            node -> val = i % 10;
            head->next = node;
            head = head->next;
            i /= 10;
        }
        return newList->next;
    }
};

2、环形链表

给定一个链表,判断链表中是否有环。

思路:快慢指针

class Solution {
public:
    bool hasCycle(ListNode *head) {
        ListNode *p = head;
        ListNode *L1 = head;
        ListNode *L2 = head;
        if(p == nullptr || p->next == nullptr)
            return false;
        while(L1 && L2 && L2 -> next) {
            L1 = L1 -> next;
            L2 = L2 -> next -> next;
            if(L1 == L2) {
                return true;
            }
        }
        return false;
        
    }
};
<think>好的,我需要帮助用户找到与C语言链表相关的练习题或面试题。用户提到了他们想寻找练习题和示例代码,所以我需要整理一些常见的链表题目,并提供相应的思路和代码示例。同时,根据用户提供的引用内容,我需要确保引用的正确使用,并在回答末尾添加相关问题。 首先,回顾用户提供的引用资料,引用1到引用5涉及链表的基础知识、内存操作(如realloc)、链表合并、快慢指针应用以及链表旋转等问题。这些可以作为题目来源。 接下来,我需要列出常见的链表练习题类型,并确保每个题目都有对应的解决思路和代码示例。例如: 1. 链表反转:这是基础题目,可以用迭代或递归方法解决。引用3中的快慢指针可能相关,但更直接的是反转指针方向。 2. 合并两个有序链表:引用4提到了这个问题,可以直接使用递归或迭代方法。 3. 检测环形链表:快慢指针法,引用3中的方法2可能适用。 4. 删除倒数第N个节点:同样可以用快慢指针,如引用3中的代码。 5. 链表中间节点:快慢指针,快指针走两步,慢指针一步。 6. 链表排序:归并排序适合链表,引用中的合并方法可用。 7. 链表元素删除:比如删除重复项,需要遍历并比较节点值。 8. 链表实现栈/队列:考察基础数据结构实现。 9. 复杂链表复制:涉及深拷贝和哈希表或节点拆分。 10. 链表相加:处理进位和大数相加问题。 每个题目需要给出思路和代码示例。例如,链表反转的迭代法需要三个指针:prev, current, next。合并有序链表可以用递归或迭代,这里可能参考引用4的方法。 需要确保代码示例用C语言编写,符合用户要求,如引用3中的C++代码需要转换为C。例如,合并链表时,创建哑节点作为新链表的头,然后逐个比较节点值,调整指针指向。 同时,注意引用文献的正确标注。例如,合并链表的问题可以引用[^4],快慢指针的应用引用[^3]和[^5]。 最后,生成相关问题,可能包括链表操作的时间复杂度、优化方法、具体应用场景等,例如如何检测环形链表、反转链表的递归实现、合并链表的迭代方法优化等。 总结步骤: 1. 分类整理链表常见题目,确保覆盖用户引用中的内容。 2. 为每个题目编写简要思路和C语言代码示例。 3. 正确引用提供的文献。 4. 生成相关问题列表,便于用户进一步学习。 现在需要将这些内容组织成用户友好的格式,分点说明,代码用正确格式,并添加相关问题。</think>### C语言链表练习题与示例代码 以下是10个常见的链表练习题及解题思路,包含C语言代码示例和相关引用标注: --- #### 1. **链表反转** **问题**:反转单链表 **思路**:使用三个指针`prev`、`current`、`next`逐步反转指针方向。 **代码示例**: ```c struct ListNode* reverseList(struct ListNode* head) { struct ListNode *prev = NULL, *current = head, *next; while (current != NULL) { next = current->next; current->next = prev; prev = current; current = next; } return prev; } ``` **引用**:类似快慢指针思想扩展应用。 --- #### 2. **合并两个有序链表** **问题**:将两个升序链表合并为一个新链表。 **思路**:创建哑节点作为新链表头,逐个比较节点值。 **代码示例**: ```c struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2) { struct ListNode dummy = {0, NULL}; struct ListNode *tail = &dummy; while (l1 && l2) { if (l1->val <= l2->val) { tail->next = l1; l1 = l1->next; } else { tail->next = l2; l2 = l2->next; } tail = tail->next; } tail->next = l1 ? l1 : l2; return dummy.next; } ``` --- #### 3. **检测环形链表** **问题**:判断链表是否有环。 **思路**:快慢指针法,若相遇则有环。 **代码示例**: ```c bool hasCycle(struct ListNode *head) { struct ListNode *slow = head, *fast = head; while (fast && fast->next) { slow = slow->next; fast = fast->next->next; if (slow == fast) return true; } return false; } ``` **引用**:快慢指针思想参考自。 --- #### 4. **删除倒数第N个节点** **问题**:删除链表倒数第N个节点。 **思路**:快指针先走N步,然后快慢指针同步移动。 **代码示例**: ```c struct ListNode* removeNthFromEnd(struct ListNode* head, int n) { struct ListNode dummy = {0, head}; struct ListNode *fast = &dummy, *slow = &dummy; while (n--) fast = fast->next; while (fast->next) { fast = fast->next; slow = slow->next; } slow->next = slow->next->next; return dummy.next; } ``` **引用**:快慢指针实现参考[^3]。 --- #### 5. **链表的中间节点** **问题**:返回链表的中间节点。 **思路**:快指针走两步,慢指针走一步。 **代码示例**: ```c struct ListNode* middleNode(struct ListNode* head) { struct ListNode *slow = head, *fast = head; while (fast && fast->next) { slow = slow->next; fast = fast->next->next; } return slow; } ``` --- #### 6. **链表排序(归并排序)** **问题**:对链表进行升序排序。 **思路**:利用归并排序的分治策略,先拆分后合并。 **代码示例**: ```c struct ListNode* sortList(struct ListNode* head) { if (!head || !head->next) return head; // 快慢指针找中点拆分 struct ListNode *slow = head, *fast = head->next; while (fast && fast->next) { slow = slow->next; fast = fast->next->next; } struct ListNode *mid = slow->next; slow->next = NULL; return mergeTwoLists(sortList(head), sortList(mid)); } ``` --- #### 7. **删除重复元素** **问题**:删除排序链表中重复元素。 **思路**:遍历链表,跳过重复节点。 **代码示例**: ```c struct ListNode* deleteDuplicates(struct ListNode* head) { struct ListNode *current = head; while (current && current->next) { if (current->val == current->next->val) { current->next = current->next->next; } else { current = current->next; } } return head; } ``` --- #### 8. **链表实现栈** **问题**:用链表实现栈的`push`和`pop`操作。 **代码示例**: ```c typedef struct { struct ListNode *top; } Stack; void push(Stack *s, int val) { struct ListNode *node = malloc(sizeof(struct ListNode)); node->val = val; node->next = s->top; s->top = node; } int pop(Stack *s) { if (!s->top) return -1; // 栈空 struct ListNode *temp = s->top; int val = temp->val; s->top = temp->next; free(temp); return val; } ``` --- #### 9. **复杂链表的深拷贝** **问题**:复制带随机指针的链表。 **思路**:使用哈希表或节点拆分法。 **代码示例**(节点拆分法): ```c struct Node* copyRandomList(struct Node* head) { if (!head) return NULL; // 1. 复制节点并插入原链表 struct Node *current = head; while (current) { struct Node *copy = malloc(sizeof(struct Node)); copy->val = current->val; copy->next = current->next; current->next = copy; current = copy->next; } // 2. 复制random指针 current = head; while (current) { if (current->random) current->next->random = current->random->next; current = current->next->next; } // 3. 拆分链表 struct Node *newHead = head->next; current = head; while (current) { struct Node *copy = current->next; current->next = copy->next; if (copy->next) copy->next = copy->next->next; current = current->next; } return newHead; } ``` --- #### 10. **链表相加** **问题**:两个链表表示的数相加(逆序存储)。 **思路**:模拟加法进位过程。 **代码示例**: ```c struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2) { struct ListNode dummy = {0, NULL}; struct ListNode *tail = &dummy; int carry = 0; while (l1 || l2 || carry) { int sum = carry; if (l1) sum += l1->val, l1 = l1->next; if (l2) sum += l2->val, l2 = l2->next; carry = sum / 10; tail->next = malloc(sizeof(struct ListNode)); tail->next->val = sum % 10; tail->next->next = NULL; tail = tail->next; } return dummy.next; } ``` --- §§ 相关问题 § 1. 如何检测链表中是否存在环?时间复杂度是多少? 2. 反转链表的递归实现方式是什么? 3. 合并两个有序链表时如何避免内存泄漏? 4. 快慢指针法在链表中还有哪些应用场景? 5. 链表的归并排序相比数组有哪些优势?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Αиcíеиτеǎг

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

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

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

打赏作者

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

抵扣说明:

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

余额充值