zoukankan      html  css  js  c++  java
  • [算法]单链表专题

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

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

    设链表头到环入口位置距离为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;
    }
  • 相关阅读:
    java----使用socket模拟简单的http请求服务器,响应简单的文件请求操作
    Java实现的断点续传功能
    C 语言——分支和跳转
    C 语言——嵌套循环例子
    C 语言——循环
    C 语言——运算符、表达式和语句
    C 语言——字符串和格式化输入/输出
    C 语言——基础概论
    C 语言——开篇
    IDEA的安装教程
  • 原文地址:https://www.cnblogs.com/iyjhabc/p/3254762.html
Copyright © 2011-2022 走看看