逆置单链表以及求链表倒数第k个结点——题集(二)

本文提供了一种高效的单链表逆置方法,并介绍了如何仅通过一次遍历找到链表的倒数第K个节点,适用于带头结点和不带头结点的链表。

逆置单链表及求链表倒数第k个结点——题集(二)

       今天分享一下两道练习题,即逆置单链表以及求链表倒数第k个结点,要求时间复杂度为O(1)。

       首先分享一下逆置单链表的代码和运行界面。单链表分为带头结点的单链表不带头结点的单链表

       源代码如下:

#include<iostream>
using namespace std;
 
//逆置/反转单链表,要求只能遍历一次链表
struct ListNode{
int val;
ListNode* next;
ListNode(int _val)
:val(_val)
,next(NULL)
{}
};
 
ListNode* reverse(ListNode* l1){//带头结点
ListNode* head = l1;
if(l1->next==NULL) return head;
l1=l1->next;
ListNode* tail = l1;
if(l1->next==NULL) return head;
l1=l1->next;
 
tail->next=NULL;//逆置后的最后一个结点next置空//********
while(l1->next != NULL){
ListNode* next=l1->next;
 
l1->next = tail;
tail=l1;
 
l1=next;
}
l1->next=tail;//最后一个结点与倒数第二个结点链接
head->next = l1;//把最后一个结点给头结点
return head;
 
}
 
ListNode* reverse1(ListNode* l1){//不带头结点
ListNode* head = l1;
ListNode* tail = l1;
if(l1->next==NULL) return head;
l1=l1->next;
 
tail->next=NULL;//逆置后的最后一个结点next置空//********
while(l1->next != NULL){
ListNode* next=l1->next;
 
l1->next = tail;
tail=l1;
 
l1=next;
}
l1->next=tail;//最后一个结点与倒数第二个结点链接
head = l1;//让原链表的最后一个结点变成头结点
return head;
 
}
 
void Printf(ListNode* l1){//打印
while(l1!=NULL){
cout<<l1->val<<" ";
l1=l1->next;
}
printf("\n");
}
 
void Listtest(){
ListNode l0(NULL);
ListNode l1(1);
ListNode l2(2);
ListNode l3(3);
ListNode l4(4);
ListNode l5(11);
 
l0.next = &l1;
l1.next = &l2;
l2.next = &l3;
l3.next = &l4;
l4.next = &l5;
 
cout<<"逆置/反转带头结点的单链表,要求只能遍历一次链表。"<<endl;
cout<<"带头结点的单链表l1: ";
Printf(l0.next);
ListNode* tmp = reverse(&l0);
cout<<"逆置后的单链表: ";
Printf(tmp->next);
}
 
void Listtest1(){
ListNode l1(1);
ListNode l2(2);
ListNode l3(3);
ListNode l4(4);
ListNode l5(11);
 
l1.next = &l2;
l2.next = &l3;
l3.next = &l4;
l4.next = &l5;
 
cout<<"逆置/反转不带头结点的单链表,要求只能遍历一次链表。"<<endl;
cout<<"不带头结点的单链表l1: ";
Printf(&l1);
ListNode* tmp = reverse1(&l1);
cout<<"逆置后的单链表: ";
Printf(tmp);
}
 
int main(){
Listtest();//带头结点的链表逆置//7.14//逆置/反转单链表+查找单链表的倒数第k个节点,要求只能遍历一次链表
cout<<endl<<"******************************"<<endl<<endl;
Listtest1();//带头结点的链表逆置
cout<<"******************************"<<endl;
system("pause");
return 0;
}

运行界面

 

       其次是求链表的倒数第k个结点的源代码和运行界面。

       源代码如下:

#include<iostream>
using namespace std;
 
//查找单链表的倒数第k个节点,要求只能遍历一次链表
struct ListNode{
int val;
ListNode* next;
ListNode(int _val)
:val(_val)
,next(NULL)
{}
};
 
ListNode* FindK(ListNode* l1,int k){//类快慢指针
ListNode* point=l1;
if(l1 == NULL || k==0)return NULL;
int num=1;
 
while(l1->next != NULL){
if(num < k){
num++;
l1 = l1->next;
continue;
}
break;
}
if(num < k)return NULL;//链表长度小于k
 
while(l1->next != NULL){
num++;
point=point->next;
l1=l1->next;
}
 
return point;
}
 
void Listtest(){
ListNode l1(1);
ListNode l2(2);
ListNode l3(3);
ListNode l4(4);
ListNode l5(11);
 
l1.next = &l2;
l2.next = &l3;
l3.next = &l4;
l4.next = &l5;
 
cout<<"查找单链表的倒数第k个节点,要求只能遍历一次链表。"<<endl;
cout<<"不带头结点的单链表l1: ";
Printf(&l1);
ListNode* prc = FindK(&l1, 0);
cout<<"FindK(&l1, 0):";
if(prc!=NULL)
cout<<prc->val<<endl;
else
cout<<"为NULL,找不到。"<<endl;
 
prc = FindK(&l1, 2);
cout<<"FindK(&l1, 2):";
if(prc!=NULL)
cout<<prc->val<<endl;
else
cout<<"为NULL,找不到。"<<endl;
 
prc = FindK(&l1, 4);
cout<<"FindK(&l1, 4):";
if(prc!=NULL)
cout<<prc->val<<endl;
else
cout<<"为NULL,找不到。"<<endl;
 
prc = FindK(&l1, 8);
cout<<"FindK(&l1, 8):";
if(prc!=NULL)
cout<<prc->val<<endl;
else
cout<<"为NULL,找不到。"<<endl;
 
}
 
int main(){
Listtest();//查找单链表的倒数第k个节点
system("pause");
return 0;
}

运行界面

 

      分享如上!望各位学的开心!

1. **链表原地**: 解思路:通过双指针法,一个指针指向当前节点,另一个指针指向其前一个节点。当第个指针到达头节点时,第一个指针就移动到了新的头节点位。然后两个指针一起向后移动,直到相遇。这个过程不需要额外空间,是原地操作。 Python 代码示例: ```python class ListNode: def __init__(self, val=0, next=None): self.val = val self.next = next def reverseList(head): prev = None curr = head while curr: temp = curr.next curr.next = prev prev = curr curr = temp return prev ``` 2. **链表的中间结点**: 解思路:可以使用快慢指针,让快指针每次走两步,慢指针每次走一步,当快指针达到链表尾部时,慢指针恰好位于链表的中间。找到慢指针即可。 Python 代码示例: ```python def middleNode(head): if not head or not head.next: return head slow, fast = head, head.next while fast and fast.next: slow = slow.next fast = fast.next.next return slow ``` 3. **链表倒数第k个结点**: 解思路:先遍历链表得到长度,再从头开始遍历k次,最后返回第k个结点。如果k大于链表长度,则返回None。 Python 代码示例: ```python def kthToLast(head, k): length = 0 node = head while node: length += 1 node = node.next if k > length: return None node = head for _ in range(length - k): node = node.next return node ``` 4. **2个有序链表的合并**: 解思路:创建一个新的链表,分别比较两个链表的头部元素,将较小的元素添加到新链表并移动对应的链表指针,直到其中一个链表结束,然后将另一个链表剩余部分依次添加。 Python 代码示例: ```python class ListNode: # ... (之前ListNode的构造函数) def mergeTwoLists(l1, l2): dummy = ListNode(0) curr = dummy while l1 and l2: if l1.val < l2.val: curr.next = l1 l1 = l1.next else: curr.next = l2 l2 = l2.next curr = curr.next if l1: curr.next = l1 elif l2: curr.next = l2 return dummy.next ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值