目录
- 一、移除链表元素
- 思路1:
- 思路2:
- 二、反转链表
- 三、链表的中间节点
- 四、链表中倒数第k个节点
- 五、回文结构
- 六、合并两个有序链表
一、移除链表元素
题目:
思路1:
在原来的链表上进行修改,节点的数据是val的删除,然后前后再连接起来。
需要考虑的因素:
1.要删除的节点位置在第一个节点;
2.要删除的节点位置在中间任意一个节点;
3.要删除的节点位置在最后一个节点
用一个变量cur遍历链表,要删除的节点是头节点,就是头删;是中间的某个节点就把要删除的节点free释放,然后连接前后的节点(定义另一个变量prev为cur的前一个);是最后一个节点,就是尾删,但是这里的尾删与中间某个节点删除是一样的。
struct ListNode* removeElements(struct ListNode* head, int val)
{
struct ListNode* cur=head;
struct ListNode* prev=NULL;
while(cur)
{
if(cur->val==val)
{
if(cur==head)
{
head=cur->next;
free(cur);
cur=head;
}
else
{
prev->next=cur->next;//cur是尾节点next就是空
free(cur);
cur=prev->next;
}
}
else
{
prev=cur;
cur=prev->next;
}
}
return head;
}
思路2:
将不是要移除的元素连接到新的链表
这里我们要定义一个新的头指针(newhead),还要一个变量cur去遍历原链表,找不是要移除的元素;再定义一个变量tail使每次插入的新节点链接起来。
注意:在最后要把tail的next置空,因为尾节点的next必须指向空指针
struct ListNode* removeElements(struct ListNode* head, int val)
{
struct ListNode* cur = head;
struct ListNode* newhead=NULL;
struct ListNode* tail = newhead;
while(cur)
{
if(cur->val==val)
{
cur=cur->next;
}
else
{
if(tail==NULL)
{
newhead=tail=cur;
}
else
{
tail->next=cur;
tail=tail->next;
}
cur=cur->next;
}
}
if(tail)
{
tail->next=NULL;
}
return newhead;
}
二、反转链表
题目:
采用头插法
定义一个新的头指针newhead指向NULL,用一个变量cur遍历原链表,再定义一个变量del为cur的下一个节点(这样cur循环一次可以到原来链表的下一个节点)。头插时,让cur的next指向newhead,再把newhead移到cur的位置上去,直到把原链表的所有节点头插完,返回的newhead就是原链表的反转。
struct ListNode* reverseList(struct ListNode* head)
{
//头插
struct ListNode* newhead=NULL;
struct ListNode* cur=head;
while(cur)
{
struct ListNode* del=cur->next;
cur->next=newhead;
newhead=cur;
cur=del;
}
return newhead;
}
三、链表的中间节点
题目:
快慢指针法
定义两个指针变量fast(快指针)和slow(慢指针),快指针一次走两步,慢指针一次走一步。当快指针或者快指针的next有一个为空指针时,跳出循环,返回慢指针,就是中间节点。
struct ListNode* middleNode(struct ListNode* head)
{
struct ListNode* slow = head;
struct ListNode* fast = head;
while(fast&&fast->next)
{
fast=fast->next->next;
slow=slow->next;
}
return slow;
}
四、链表中倒数第k个节点
题目:
快慢指针相对距离法
定义两个指针变量fast和slow,先让fast走k步(如果fast已经为空k还没结束就返回空),然后fast和slow一起走(速度相同),当fast为空时跳出循环,此时的slow就是倒数第k个节点。
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k )
{
struct ListNode* slow = pListHead;
struct ListNode* fast = pListHead;
while(k)//先走k步
{
if(fast==NULL)
{
return NULL;
}
fast=fast->next;
k--;
}
while(fast!=NULL)//相对距离
{
fast=fast->next;
slow=slow->next;
}
return slow;
}
五、回文结构
题目:
这道题其实是前面两个题的综合
采用找中间节点和反转链表,然后比较是否回文
先找到中间节点,然后在这个中间节点开始反转后面的节点,比较从头节点开始到中间节点的个数,如果相同,就是回文,返回true;否则返回false。
class PalindromeList {
public:
ListNode* find(ListNode* head)
{
ListNode* slow=head;
ListNode* fast=head;
while(fast&&fast->next)
{
slow=slow->next;
fast=fast->next->next;
}
return slow;
}
ListNode* reverse(ListNode* head)
{
ListNode* newhead=NULL;
ListNode* cur=head;
while(cur)
{
ListNode* del=cur->next;
cur->next=newhead;
newhead=cur;
cur=del;
}
return newhead;
}
bool chkPalindrome(ListNode* head) {
ListNode* rid=find(head);
ListNode* mrid=reverse(rid);
ListNode* cur=head;
while(cur!=rid)
{
if(cur->val!=mrid->val)
{
return false;
}
cur=cur->next;
mrid=mrid->next;
}
return true;
}
};
六、合并两个有序链表
题目:
两个链表的节点从头开始比较,取小的尾插到新链表;如果有一个链表的节点还没尾插完,就直接将这个链表的剩余节点尾插到新链表去。
如果刚开始有某个链表为空,就直接返回另一个链表
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
{
if(list1==NULL)
{
return list2;
}
if(list2==NULL)
{
return list1;
}
struct ListNode* head=NULL;
struct ListNode* tail=NULL;
while(list1&&list2)
{
if(list1->val<=list2->val)
{
if(tail==NULL)
{
head=tail=list1;
}
else
{
tail->next=list1;
tail=tail->next;
}
list1=list1->next;
}
else
{
if(tail==NULL)
{
head=tail=list2;
}
else
{
tail->next=list2;
tail=tail->next;
}
list2=list2->next;
}
}
if(list1)
{
tail->next=list1;
}
if(list2)
{
tail->next=list2;
}
return head;
}
感谢观看~