一,移除链表元素
思路一
遍历数组,如果遇到链表中的元素等于val的节点就执行删除操作
typedef struct ListNode ListNode;struct ListNode* removeElements(struct ListNode* head, int val) {if(head==NULL){return NULL;} ListNode*pnewhead=(ListNode*)malloc(sizeof(ListNode));pnewhead->next=head;ListNode*pcur=head;ListNode*prev=pnewhead;while(pcur){if(pcur->val==val){prev->next=pcur->next;free(pcur);pcur=NULL;pcur=prev->next;}else{prev=pcur;pcur=pcur->next;}}return pnewhead->next;}
思路二
建立一个新的链表,遇到的节点里面存的数据如果不等于val的值的话就将这个节点尾插到建立的新的链表的后面
typedef struct ListNode ListNode;struct ListNode*removeElement(struct ListNode*head,int val){ListNode*pcur=head;ListNode*newhead,*newtail;//建立新的链表newhead=newtail=NULL;while(pcur)//遍历链表{if(pcur->val!=val){if(newhead==NULL){newhead=newtail=pcur;//新链表为空,将当前的节点赋值给新的链表}else{newtail->next=pcur;//不为空,插到新链表的后面newtail=newtail->next;}}pcur=pcur->next;}if(newtail)//如果链表的不为空的话,就让尾节点的后面为空{newtail->next=NULL;}return newhead;}
代码说明
if(newtail)//如果链表的不为空的话,就让尾节点的后面为空{newtail->next=NULL;}
因为链表在插入的时候,当前节点的后面还有节点,插入的时候会后面的节点会跟在后面,所以要将原链表的尾节点的后面的节点置为空,比如下面的
当要将上面的链表中的4处于的节点的位置插入到下面0位于的节点的后面,插入的不是4,而是4和4链接的5位于的节点,插入的是后面的一串,这和顺序表不一样
二.反转链表
思路
这里可以定义三个指针,一个指向当前节点,一个指向当前节点的上一个节点,一个指向当前节点的下一个节点,直接让当前节点指向上一个节点
typedef struct ListNode ListNode;
struct ListNode* reverseList(struct ListNode* head) {ListNode*prev=NULL;//前驱节点ListNode*pcur=head;//当前节点ListNode*back=NULL;//当前节点的下一个节点if(head==NULL){return NULL;}if(head->next==NULL){return head;}while(pcur){pcur->next=prev;prev=pcur;pcur=back;if(back!=NULL){back=back->next;}}return prev;
}
三.将两个升序链表合并成为一个新的升序链表
思路:定义一个新的无效链表头(里面没有数据,在后续的程序中不需要判断该链表是否是空链表,能够对代码进行优化,有返回值的时候直接返回这个链表头的下一个节点就可以了),以及两个指针,分别指向两个升序链表,比较两个链表里面的值,谁小就把谁放到新链表的后面,然后这个指针指向下一个节点就行了
typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {ListNode*pcur1=list1;//定义指针1ListNode*pcur2=list2;//定义指针2if(list1==NULL){return list2;//为空链表的话返回另一个链表}if(list2==NULL){return list1;//为空的话返回另一个链表}ListNode*phead=(ListNode*)malloc(sizeof(ListNode));ListNode*pcur3=phead;while(pcur1&&pcur2){if(pcur1->val<=pcur2->val){pcur3->next=pcur1;pcur3=pcur3->next;pcur1=pcur1->next;}else{pcur3->next=pcur2;pcur3=pcur3->next;pcur2=pcur2->next;}}if(pcur2==NULL){pcur3->next=pcur1;//插入的是该节点以及该节点后面的节点,一步到位}if(pcur1==NULL){pcur3->next=pcur2;}return phead->next;}
四.链表的中间节点
思路:定义两个指针,一个快指针,一个慢指针,满指针一次走一格,快指针一次走两格,最后返回慢指针就行了
typedef struct ListNode ListNode;
struct ListNode* middleNode(struct ListNode* head) {ListNode*fast,*slow;fast=head,slow=head;if(head->next==NULL){return head;}while(fast&&fast->next){slow=slow->next;fast=fast->next->next;}return slow;}
五,分割链表
思路:定义两个新的链表,遍历原链表,原链表里面的节点里面的值和x比较,小的尾插在第一个链表后面,大于等于的尾插在第二个链表的后面,最后连接两个链表
typedef struct ListNode ListNode;
struct ListNode* partition(struct ListNode* head, int x){ListNode*pcur=head;ListNode*pcur1=(ListNode*)malloc(sizeof(ListNode));ListNode*pcur2=(ListNode*)malloc(sizeof(ListNode));ListNode*head1=pcur1;ListNode*head2=pcur2;if(head==NULL){return NULL;}if(head->next==NULL){return head;}while(pcur){if(pcur->val<x){pcur1->next=pcur;pcur1=pcur1->next;}else{pcur2->next=pcur;pcur2=pcur2->next;}pcur=pcur->next;}pcur2->next=NULL;pcur1->next=head2->next;return head1->next;
}
注意:上面的代码为什么要有下面的这句话嘞?
pcur2->next=NULL;
原因是插入链表节点的时候,后面带着的节点是跟在本节点的后面的,插的时候就顺带着了,本节点后面不置为空就会造成死循环
六.环形链表的约瑟夫问题
什么是环形链表的约瑟夫问题,先看一看下面的故事:
著名的Josephus问题 据说著名犹太 历史学家 Josephus有过以下的故事:在罗⻢⼈占领乔塔帕特后,39个犹太⼈与 Josephus及他的朋友躲到⼀个洞中,39个犹太⼈决定宁愿死也不要被⼈抓到,于是决定了⼀个⾃杀 ⽅式,41个⼈排成⼀个圆圈,由第1个⼈开始报数,每报数到第3⼈该⼈就必须⾃杀,然后再由下⼀ 个重新报数,直到所有⼈都⾃杀⾝亡为⽌。 然⽽Josephus和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与⾃⼰安排在 第16个与第31个位置,于是逃过了这场死亡游戏。
第一步:创建一个环形链表
第二部:定义一个变量,初值为1,如果该变量不等于m,该变量加1,继续遍历链表,等于,删除该节点,变量重新等于1
typedef struct ListNode ListNode;
//产生一个节点ListNode*buynode(int x){ListNode*newnode=(ListNode*)malloc(sizeof(ListNode));newnode->val=x;newnode->next=NULL;return newnode;}
//建立一个环形链表ListNode*creatcircle(int n){ListNode*phead=buynode(1);ListNode*pcur=phead;phead->val=1;for(int i=2;i<=n;i++){pcur->next=buynode(i);pcur=pcur->next;}pcur->next=phead;return phead;}
int ysf(int n, int m ){ListNode*phead=creatcircle(n);ListNode*pcur=phead;ListNode*prev=NULL;int count=1;while(pcur->next!=pcur){if(count==m){prev->next=pcur->next;free(pcur);pcur=NULL;count=1;pcur=prev->next;}else {prev=pcur;pcur=pcur->next;count++;}}return pcur->val;
}
七.结语
在链表中,最值得注意的是,尾插链表,插入的是该节点和该节点后面的节点,也就是一串节点
在插入链表的时候,记得要将该节点后面置为空