常见的链表题目

本文介绍了单链表的六种常见操作,包括单链表的反序、建环、检测环、解环、检测两条链表是否相交以及如何在不提供头节点的情况下删除指定节点。每种操作都附带了详细的实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一些常见的单链表题目,总结思路和实现代码。

1.单链表的反序

2.给单链表建环

3.检测单链表是否有环

4.给单链表解环

5.检测两条链表是否相交

6.不输入头节点,删除单链表的指定节点(只给定待删除节点指针)

1.单链表的反序

//逆转链表,并返回逆转后的头节点 node* reverse(node *head) { if(head == NULL || head->next == NULL) { return head; } node *cur = head; node *pre = NULL; node *tmp; while(cur->next) { tmp = pre; pre = cur; cur = cur->next; pre->next = tmp; //操作pre的next逆转 } cur->next = pre; //结束时,操作cur的next逆转 return cur; }

2.给单链表建环

//给单链表建环,让尾指针,指向第num个节点,若没有,返回false bool bulid_looplink(node *head, int num) { node *cur = head; node *tail = NULL; int i = 0; if(num <= 0 || head == NULL) { return false; } for(i = 1; i < num; ++i) { if(cur == NULL) { return false; } cur = cur->next; } tail = cur; while(tail->next) { tail = tail->next; } tail->next = cur; return true; }

3.检测单链表是否有环

//检测单链表是否有环,快慢指针 bool detect_looplink(node *head) { node *quick_node = head->next, *slow_node = head; if(head == NULL || head->next == NULL) { return false; } while(quick_node != slow_node) { if(quick_node == NULL || slow_node == NULL) break; quick_node = quick_node->next->next; slow_node = slow_node->next; } if(quick_node != NULL && slow_node != NULL) //非尾节点相遇 return true; return false; }

4.给单链表解环

ps:为了增加节点位图的效率,本应使用hash或则红黑树,这里不造车了,直接用 set容器

//找到有环节点,并解环,找到并解环,返回true,无环,返回false //思路:先找到环节点:被2个节点指向的节点(一定有环的条件)ps:不考虑中间环,因为只有一个next节点,只可能是尾环 bool unloop_link(node *head) { set<node *> node_bitmap; //node的地址位图 unsigned int num = 0; node *cur = head, *pre = NULL; while(cur != NULL) { if(!node_bitmap.count(cur) ) //该节点未被遍历过 { node_bitmap.insert(cur); ++num; } else //指向已被遍历过的节点,此时pre节点为尾节点 { pre->next = NULL; return true; } pre = cur; cur = cur->next; } return false; }

5.检测两条链表是否相交

//检测两条链表是否相交,是则返回第一个交点,否则返回NULL //思路:把2个链表各遍历一遍,记下长度length1和length2,若2者的尾节点指针相等,则相交。 // 之后再把长的链表从abs(len1-len2)的位置开始遍历,第一个相等的指针为目标节点 node* detect_intersect_links(node *first_link, node *second_link) { int legnth1 = 1, length2 = 1, pos = 0; node *cur = NULL, *longer_link = first_link, *shorter_link = second_link; if(first_link == NULL || second_link == NULL) { return NULL; } while(first_link->next || second_link->next) //遍历2个链表 { if(first_link->next) { first_link = first_link->next; ++legnth1; } if(second_link->next) { second_link = second_link->next; ++length2; } } if(first_link != second_link) //比较尾节点 { return NULL; } pos = legnth1 - length2; if(legnth1 < length2) //保证 longer_link为长链表 { pos = length2 - legnth1; cur = longer_link; longer_link = shorter_link; shorter_link = cur; } while(pos-- > 0) longer_link = longer_link->next; while(longer_link || shorter_link) { if(longer_link == shorter_link) //找到第一个交点 { return longer_link; } longer_link = longer_link->next; shorter_link = shorter_link->next; } return NULL; }

6.不输入头节点,删除单链表的指定节点(只给定待删除节点指针)

//无头节点,随机给出单链表中一个非头节点,删除该节点,当传入空节点,或者尾节点时,返回false //思路:由于没有头节点,非循环单链表,无法获取目标节点的前节点,所以只能把它的next节点数据前移,并删除next节点 //ps:当传入节点为尾节点,无法用此方法删除 bool withouthead_delete_node(node *target_node) { node *cur = NULL; if(target_node == NULL || target_node->next == NULL) //空节点或者尾节点,失败 { return false; } cur = target_node->next; target_node->name = cur->name; target_node->next = cur->next; delete cur; return true; }

### C语言中链表相关的练习题学习资料 #### 关于链表的基础概念 链表是一种常见的线性数据结构,在C语言中可以通过指针实现动态存储管理。相比于数组,链表具有灵活的内存分配特点,适合处理未知大小的数据集合[^1]。 --- #### 示例代码:创建简单的单向链表 以下是基于C语言的一个简单单向链表的创建、遍历以及释放操作: ```c #include <stdio.h> #include <stdlib.h> // 定义链表节点结构体 typedef struct Node { int data; struct Node* next; } Node; // 创建新节点函数 Node* create_node(int value) { Node* new_node = (Node*)malloc(sizeof(Node)); if (!new_node) { printf("Memory error\n"); exit(1); } new_node->data = value; new_node->next = NULL; return new_node; } // 插入节点到链表末尾 void append_node(Node** head_ref, int value) { Node* new_node = create_node(value); if (*head_ref == NULL) { *head_ref = new_node; return; } Node* temp = *head_ref; while (temp->next != NULL) { temp = temp->next; } temp->next = new_node; } // 打印链表 void print_list(Node* node) { while (node != NULL) { printf("%d -> ", node->data); node = node->next; } printf("NULL\n"); } // 释放链表内存 void free_list(Node* head) { Node* current = head; Node* next = NULL; while (current != NULL) { next = current->next; free(current); current = next; } } int main() { Node* head = NULL; // 添加一些节点 append_node(&head, 10); append_node(&head, 20); append_node(&head, 30); // 打印链表 print_list(head); // 释放链表 free_list(head); return 0; } ``` 上述代码展示了如何定义链表节点、插入节点、打印链表以及安全释放链表所占内存[^2]。 --- #### 经典链表练习题解析 ##### 题目1:查找倒数第K个节点 此问题的核心在于双指针法的应用。通过让一个指针先移动`k`步,再同步移动两个指针直到前一个到达链表末端即可找到目标节点[^3]。 ```c Node* find_kth_to_tail(Node* head, unsigned int k) { if (head == NULL || k == 0) return NULL; Node* fast = head; Node* slow = head; for (unsigned int i = 0; i < k; ++i) { if (fast == NULL) return NULL; // 判断k是否大于链表长度 fast = fast->next; } while (fast != NULL) { fast = fast->next; slow = slow->next; } return slow; } ``` --- ##### 题目2:合并两个有序链表 该问题是考察链表的操作能力的经典题目之一。可以采用迭代或递归的方式解决。以下是一个迭代版本的解决方案[^4]。 ```c Node* merge_two_lists(Node* list1, Node* list2) { Node dummy_head = {0}; Node* tail = &dummy_head; while (list1 && list2) { if (list1->data <= list2->data) { tail->next = list1; list1 = list1->next; } else { tail->next = list2; list2 = list2->next; } tail = tail->next; } tail->next = (list1 ? list1 : list2); return dummy_head.next; } ``` --- #### 学习资源推荐 对于初学者来说,可以从基础入手逐步深入理解链表的工作原理及其应用场景。例如,参考站内的文章提供了丰富的实例讲解[^5]。 --- ####
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值