链表
删除链表中等于给定值 val 的所有结点
1.创建一个哨兵位的头
2.将不是val的值链接进去
3.释放掉相同值的节点
4.记得尾部指针制空
struct ListNode* guard,*tail;
tail=guard=(struct ListNode*)malloc(sizeof(struct ListNode));//哨兵位头节点
guard->next=NULL;
struct ListNode* cur=head;
while(cur)
{
if(cur->val!=val)
{
tail->next=cur;
tail=tail->next;
cur=cur->next;
}
else
{
struct ListNode* next=cur->next;
free(cur);
cur=next;
}
}
tail->next=NULL;
struct ListNode* newnode=guard->next;//释放掉哨兵位的头
free(guard);
return newnode;
}
反转链表
两种方法:
1.用头插的方法将节点一个一个放入其中
2.直接倒置
struct ListNode* cur=head;
struct ListNode* rhead=NULL;
while(cur)
{
struct ListNode* new=cur->next;//new里面存放下一个节点的地址
cur->next=rhead;//先把第一个的next置为NULL
rhead=cur;//rhead换到当前节点的地址
cur=new;//cur转换到new的地址
}
return rhead;//返回新的节点
if(head==NULL)
return NULL;//防止开始为空
struct ListNode *n1,*n2,*n3;
n1=NULL;
n2=head;
n3=n2->next;
while(n2)
{
n2->next=n1;
n1=n2;
n2=n3;
if(n3!=NULL)
n3=n3->next;
}
return n1;
链表的中间节点
方法:快慢指针
struct ListNode* middleNode(struct ListNode* head){
//快慢指针
if(head==NULL)
return NULL;
struct ListNode* fastlist,*slowlist;
fastlist=slowlist=head;
while(fastlist&&fastlist->next)//如果是奇数个,那么fast后面一个为空;偶数个那么fast->next为空
{
fastlist=fastlist->next->next;
slowlist=slowlist->next;
}
return slowlist;
}
链表中倒数第K个节点
方法:快慢指针,跳过K个节点就好
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
// write code here
//快慢指针的应用
if(pListHead==NULL)
return NULL;
struct ListNode* fast,*slow;
fast=slow=pListHead;
while(k--)//差几个节点,fast先走几步
{
if(fast)
fast=fast->next;
else//k可能会大于链表
return NULL;
}
while(fast)
{
fast=fast->next;
slow=slow->next;
}
return slow;
}
合并两个有序链表
方法:哨兵位的头一大一小进行查找
/创建哨兵位头节点
struct ListNode* guard,*tail;
struct ListNode* head;
guard=tail=(struct ListNode*)malloc(sizeof(struct ListNode));
guard->next=NULL;
//取小的尾插
while(list1&&list2)
{
if(list1->val<list2->val)
{
tail->next=list1;//尾插
tail=tail->next;//尾进行更替
list1=list1->next;
}
else
{
tail->next=list2;
tail=tail->next;
list2=list2->next;
}
}
if(list1)
{
tail->next=list1;
}
if(list2)
{
tail->next=list2;
}
head=guard->next;
free(guard);
return head;
链表分割
方法:哨兵位头+分割+整合
//思想:把单链表尾 插变成大于和小于两个链表,再把大的链表尾插到小的链表后面
ListNode* bighead,*bigtail,*smallhead,*smalltail;
bighead=bigtail=(ListNode*)malloc(sizeof(ListNode));
smallhead=smalltail=(ListNode*)malloc(sizeof(ListNode));
bigtail->next=smalltail->next=NULL;
ListNode* cur=pHead;
while(cur)
{
if(cur->val<x)
{
smalltail->next=cur;
smalltail=smalltail->next;
}
else
{
bigtail->next=cur;
bigtail=bigtail->next;
}
cur=cur->next;
}
smalltail->next=bighead->next;
bigtail->next=NULL;//把大链接最后的指向改成NULL,否则会导致死循环。
pHead=smallhead->next;
free(bighead);
free(smallhead);
return pHead;
}
链表的回文
方法:先快慢找到回文的中间节点+后半段逆置+比较
注意:如果数量是奇数,回文后刚好前面是n/2-1个,后面是n/2+1,但是少的一节的最后一个刚好是指向多的一个的最后一个
class PalindromeList {
//快慢指针
ListNode* Mid(ListNode* head)
{
ListNode* fast,*slow;
fast=slow=head;
while(fast&&fast->next)
{
fast=fast->next->next;
slow=slow->next;
}
return slow;
}
//逆置
ListNode* Reser(ListNode* head)
{
ListNode* n1,*n2,*n3;
n1=NULL;
n2=head;
n3=n2->next;
while(n2)
{
n2->next=n1;
n1=n2;
n2=n3;
if(n3)
{
n3=n3->next;
}
}
return n1;
}
public:
bool chkPalindrome(ListNode* A) {
//快慢指针找中间+逆置后半段+比较
// write code here
ListNode* mid=Mid(A);
ListNode* rhead=Reser(mid);
while(A&&rhead)
{
if(A->val!=rhead->val)
return false;
A=A->next;
rhead=rhead->next;
}
return true;
}
环形链表
方法:快慢指针
思路:追击问题,如果慢的比快的少走一步,那如果是环形,肯定能追上,因为即使套圈,那么只差一个,会在相同位置遇到
bool hasCycle(struct ListNode *head) {
//追击问题,快慢指针
struct ListNode* fast=head;
struct ListNode* slow=head;
while(fast&&fast->next)
{
fast=fast->next->next;
slow=slow->next;
if(fast==slow)
return true;
}
return false;
}
环形链表进阶版
方法:找到相遇位置,快指针从相遇位置先走,慢指针从出发位置走,碰到的第一个节点就是要找的节点
原因:
设直线为L,相遇的点到要找的节点距离为N,一圈为长度为C
相交问题
方法:看长短差多少,让长的先走差值,然后两者同时走,如果相交那么就可以碰到,如果不行就是没相交
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB)
{
//把两个链表搞成相等的,让他一一对照
struct ListNode* s1=headA,*s2=headB;
int A=0,B=0;
//找出两个链表差多少
while(s1->next)
{
A++;
s1=s1->next;
}
while(s2->next)
{
B++;
s2=s2->next;
}
//不相交就输出错误
if(s1!=s2)
{
return NULL;
}//相交
int gde=abs(A-B);
struct ListNode* longside=headA;
struct ListNode* shortside=headB;
if(B>A)//谁更长就把长的付给谁
{
longside=headB;
shortside=headA;
}
//长的先走
while(gde--)
{
longside=longside->next;
}
//同时走。找交点
while(longside!=shortside)
{
longside=longside->next;
shortside=shortside->next;
}
return longside;
}
复制带随机指针的链表
方法:先把节点一一对照挂到原链表上,把random对应上去,拆下来尾插
//1.挂上源节点
struct Node* cur= head;
while(cur)
{
struct Node* next = cur->next;
struct Node* copy = (struct Node*)malloc(sizeof(struct Node));
copy->val = cur->val;
copy->next=next;
cur->next=copy;
cur=next;
}
//2.查找random
cur = head;
while(cur)
{
struct Node* copy= cur->next;
if(cur->random == NULL)//万一有节点指向空,那么需要把copy也指向空
{
copy->random = NULL;
}
else
{
copy->random = cur->random->next;
}
cur=cur->next->next;
}
//3.取下尾插
cur=head;
struct Node* rhead,*tail;
rhead=tail=NULL;
while(cur)
{
struct Node* copy=cur->next;
struct Node* next=copy->next;
cur->next = next;
if(tail==NULL)
{
rhead=tail=copy;
//cur->next=copy->next;
}
else
{
tail->next=copy;
tail=tail->next;
}
cur=next;
}
return rhead;