[算法]单链表专题

如何判断链表环的入口位置?

一个指针从头开始单步走,一个指针从第一次相遇位置开始单步走,再相遇的位置就是环入口,证明如下:

设链表头到环入口位置距离为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;
}

 

posted @ 2013-08-13 11:17  iyjhabc  阅读(167)  评论(0编辑  收藏  举报