一、移除链表元素
移除链表元素
法一:不使用虚拟头节点
ListNode* removeElements(ListNode* head, int val) {//若删除头节点while(head!=NULL&&head->val==val)//连续删除头节点的条件{head=head->next;} //删除其他节点(先判断是不是空链表)if(head!=NULL){ListNode* cur=head;while(cur->next!=NULL){if(cur->next->val==val){cur->next=cur->next->next;}else{cur=cur->next;}}}return head;}
法二:使用虚拟头节点
ListNode* dummy=new ListNode(0,head); //创建虚拟头节点并连接到原链表ListNode* cur=dummy; //用来遍历的指针while(cur->next!=NULL){if(cur->next->val==val){cur->next=cur->next->next;}else{cur=cur->next;}}return dummy->next;
二、设计链表
设计链表
单链表:
//先定义节点结构体
struct LinkNode{
int val;
LinkNode* next;
LinkNode(int val=0,LinkNode* next=NULL):val(val),next(next){}
};class MyLinkedList {int size; //链表的长度 LinkNode* dummy; //虚拟头节点
public:MyLinkedList() {//初始化链表:长度为0,初始化虚拟头节点size=0;dummy=new LinkNode();}// 析构函数,释放所有节点的内存~MyLinkedList() {LinkNode* cur = dummy;while (cur != nullptr) {LinkNode* temp = cur;cur = cur->next;delete temp; // 不断删除头节点,手动释放内存}}int get(int index) {//先判断index是否合理if(index<0||index>size-1)return -1;else{LinkNode* cur=dummy;int loop=index+1;while(loop--){cur=cur->next;}return cur->val;}}void addAtHead(int val) {//先新建节点LinkNode* newNode=new LinkNode(val);//插入newNode->next=dummy->next;dummy->next=newNode;size++;}void addAtTail(int val) {LinkNode* newNode=new LinkNode(val);LinkNode* cur=dummy;while(cur->next!=NULL){cur=cur->next;}cur->next=newNode;size++;}void addAtIndex(int index, int val) {//先判断index是否合理if(index<0||index>size)return;LinkNode* newNode=new LinkNode(val);LinkNode* cur=dummy;int loop=index;while(loop--){cur=cur->next;}newNode->next=cur->next;cur->next=newNode;size++;}void deleteAtIndex(int index) {//先判断index是否合理if(index<0||index>size-1)return;int loop=index; //让cur指向下标为index-1的节点LinkNode* cur=dummy;while(loop--){cur=cur->next;}cur->next=cur->next->next;size--;}
};/*** Your MyLinkedList object will be instantiated and called as such:* MyLinkedList* obj = new MyLinkedList();* int param_1 = obj->get(index);* obj->addAtHead(val);* obj->addAtTail(val);* obj->addAtIndex(index,val);* obj->deleteAtIndex(index);*/
三、反转链表
反转链表
法一:逐个逆转方向
ListNode* reverseList(ListNode* head) {//法一:逐个逆转方向ListNode*cur=head,*pre=NULL,*temp;while(cur){temp=cur->next; //一存cur->next=pre; //二改pre=cur; //三移cur=temp;}return pre;}
递归写法:
//递归写法ListNode* reverse(ListNode*cur,ListNode*pre){if(cur==NULL) //终止条件return pre; ListNode* temp=cur->next; //先存cur->next=pre; //后改向return reverse(temp,cur); //进入下一轮逆转(将指针移动放进递归参数变化中)}ListNode* reverseList(ListNode* head) {return reverse(head,NULL); //调用递归}
法二:虚拟头节点+头插法
ListNode* reverseList(ListNode* head) {//法二:虚拟头节点+头插法ListNode*nummy=new ListNode();ListNode*cur=head,*temp;while(cur){temp=cur->next; //一存cur->next=nummy->next; //二头插nummy->next=cur;cur=temp; //三移}return nummy->next;}
四、两两交换链表中的节点
两两交换链表中的节点
法一:
ListNode* swapPairs(ListNode* head) {//借用虚拟头节点,1+2的模式交换ListNode*dummy=new ListNode(0,head);ListNode*cur=dummy;while(cur->next!=NULL&&cur->next->next!=NULL) //节点数为偶数或奇数时的循环条件(注意cur->next要写在前面,否则可能空指针异常){//交换两个节点ListNode *temp=cur->next;//先保存一个节点,防止丢失(也可以借助两个临时指针存储信息,不容易错乱)cur->next=cur->next->next; //交换节点(三条线)temp->next=cur->next->next;cur->next->next=temp;cur=cur->next->next; //指针移动}return dummy->next;}
法二:递归法
五、删除链表的倒数第N个节点
删除链表的倒数第N个节点
法一:利用快慢指针
ListNode* removeNthFromEnd(ListNode* head, int n) {//利用快慢指针的差值:n+1步;利用虚拟头指针,统一删除操作ListNode *dummy=new ListNode(0,head);ListNode*fast=dummy,*slow=dummy;//快指针先走n+1步for(int i=0;i<n+1;i++){fast=fast->next;}//快慢指针再同时走,直至fast走到末尾while(fast){slow=slow->next;fast=fast->next;}//删除节点slow->next=slow->next->next;return dummy->next;}
法二:先计算出链表长度
int getLength(ListNode*head){int length=0;while(head){length++;head=head->next;}return length;}ListNode* removeNthFromEnd(ListNode* head, int n) {ListNode*dummy=new ListNode(0,head); //利用虚拟头节点,统一删除操作ListNode*cur=dummy;//先计算出链表长度int lenght=getLength(head);//再找要删除节点的前一个节点(转换成顺数第几个节点)最后一位:正序lenght,逆序1 所以逆序第n位,对应正序第lenght+1-n位for(int i=0;i<lenght-n;i++) //cur走length-n步到达被删节点的前一个节点{cur=cur->next;}//最后删除节点cur->next=cur->next->next;return dummy->next;}
六、环形链表
环形链表
快慢指针:快指针速度为2,慢指针速度为1,若两个指针相遇则说明链表有环
(快指针比慢指针快即可,但是2:1是最高效的)
双指针:index1从头节点出发,index2从相遇节点出发,则两者的相遇点在入环节点
ListNode *detectCycle(ListNode *head) {//若快慢指针相遇,则说明有环ListNode*fast=head,*slow=head;while(fast!=NULL&&fast->next!=NULL) //让快慢指针跑起来,结束条件是fast没到末尾(因为fast一下跳两步,所以还要保证fast->next不为空){fast=fast->next->next;slow=slow->next;if(slow==fast) //若相遇,则说明有环{ListNode*index1=head,*index2=fast; //从出发点和相遇点各派出速度同为1的指针,则两者相遇点在入环节点while(index1!=index2) //让两个指针跑起来,结束条件是index1==index2{index1=index1->next;index2=index2->next;}return index1;}}return NULL; //循环结束无环,返回null}