如何判断链表环的入口位置?
一个指针从头开始单步走,一个指针从第一次相遇位置开始单步走,再相遇的位置就是环入口,证明如下:
设链表头到环入口位置距离为a,入口位置到第一次相遇位置为b,相遇位置回到入口位置距离为c。
1、每次走一步的慢指针走了s步,则快指针走了2s步。s=a+b。相遇时慢指针一定没走完一圈。
2、快指针走的总步数为a+b+n(b+c),走到相遇位置,并走了n圈。因此a+b+n(b+c)=2*(a+b)
a=n(b+c)-b=(n-1)(b+c)+c,也就证明了上面所提的方法。
class linklist { public:int val;linklist *next;linklist():next(NULL){}void push_back(int val);void clear();~linklist(){cout<<this->val<<" has been deleted"<<endl;} };void linklist::push_back(int val){linklist *p=this;while(p->next!=NULL){p=p->next;}p->next=new linklist;p->next->val=val; }void linklist::clear(){linklist *p=this,*ptmp;while(p!=NULL){ptmp=p->next;delete p;p=ptmp;} }linklist* merge(linklist *p1,linklist *p2){if(p1==NULL){return p2;}if(p2==NULL){return p1;}linklist *head,*cur;if(p1->val<=p2->val){head=p1;cur=p1;p1=p1->next;}else{head=p2;cur=p2;p2=p2->next;}while(p1!=NULL && p2!=NULL){if(p1->val<=p2->val){cur->next=p1;cur=p1;p1=p1->next;}else{cur->next=p2;cur=p2;p2=p2->next;}}if(p1!=NULL){cur->next=p1;}if(p2!=NULL){cur->next=p2;}return head; }linklist* merge_recur(linklist *p1,linklist *p2){if(!p1){return p2;}if(!p2){return p1;}if(p1->val<=p2->val){p1->next=merge_recur(p1->next,p2);return p1;}else{p2->next=merge_recur(p1,p2->next);return p2;} }linklist* reverse(linklist *head){linklist *pre,*cur,*next;pre=NULL;cur=head;while(cur){next=cur->next;//传递next的值放开头,不放最后,可以避免cur为NULL的判断cur->next=pre;pre=cur;cur=next;}return pre; }linklist* reverse_recur(linklist *head,linklist *&newhead){if(!head){return NULL;}linklist *p=reverse_recur(head->next,newhead);if(p){p->next=head;}else{newhead=head;}head->next=NULL;return head; }linklist* find_cross(linklist *p1,linklist *p2){if(!p1 || !p2){return NULL;}int len1=1,len2=1;linklist *ptmp=p1;while(ptmp->next){len1++;ptmp=ptmp->next;}linklist *p1end=ptmp;ptmp=p2;while(ptmp->next){len2++;ptmp=ptmp->next;}if(ptmp!=p1end){return NULL;}//两个链表尾重叠了,证明链表交叉if(len1>len2){//去掉较长链表的多余部分,然后开始一一对比int count=len1-len2;while(count){p1=p1->next;count--;}}else if(len2>len1){int count=len2-len1;while(count){p2=p2->next;count--;}}while(true){if(p1==p2){return p1;}p1=p1->next;p2=p2->next;}return NULL; }linklist* find_loop(linklist *head){linklist *p1=head,*p2=head;do{p1=p1->next;if(p2->next){p2=p2->next->next;}else{return NULL;}}while(p1 && p2 && p1!=p2);if(!p1 || !p2){return NULL;}p2=head;while(p1!=p2){p1=p1->next;p2=p2->next;}return p1; }linklist* find_middle(linklist *head){linklist *fast=head,*slow=head;while(fast && fast->next){fast=fast->next->next;slow=slow->next;}return slow; }linklist* del_last_k(linklist *head,int k){/*linklist *reval;linklist *tmp=head,*pre_tmp=NULL;//用来存放当前节点的前k个节点的地址int i=k-1;linklist *p=head;while(p->next){if(i==0){//先判断i,再进行i--,不能反过来pre_tmp=tmp;tmp=tmp->next;}p=p->next;if(i>0){i--;}}if(i>0){//如果i没到0,证明k的大小比链表还长,不用进行删除return head;}if(tmp==head){//如果删除了链表头,则需返回新的链表头reval=head->next;}else{reval=head;}if(tmp){if(pre_tmp){pre_tmp->next=tmp->next;}delete tmp;tmp=NULL;}return reval;*/linklist *p=head,*reval;while(p && k>0){p=p->next;k--;}if(p==NULL && k==0){//刚好删除第一个reval=head->next;delete head;return reval;}else if(p==NULL && k>0){//k长度超出链表长度,不需删除return head;}else{//要删的在第二个到最后一个之间,把p2移动到需要删除的元素之前linklist *p2=head;while(p->next!=NULL){p=p->next;p2=p2->next;}linklist *tmp=p2->next;p2->next=p2->next->next;delete tmp;return head;} }//根据地址删除一个中间节点:把删除点后接节点的值复制到删除点,然后删除后接点 void DeleteMidNode(linklist *del){if (!del) {return;}linklist *next = del->next;if (next) {del->val= next->val;del->next= next->next;delete next;} }//在给定地址的节点前插入节点:在给定地址点后插入,然后交换前后两节点的值 void insert_before(linklist *node,linklist *insert){if (!node || !insert) {return;}linklist temp = *node;node->val = insert->val;node->next= insert;*insert = temp; }