zoukankan      html  css  js  c++  java
  • 单循环链表基本操作及部分可能出现的细节问题

    最近在学数据结构
    目前是最基础的线性表部分
    看完书之后感觉差不多了,自己写的时候还是出现了许多小问题…
    因此我觉得新手学习还是很有必要亲自操作一遍,虽然比较费时间,但是能加深理解
    下面的注释里有我出现的一些问题及相应的解决方案
    注释应该比较详细

    #include <iostream>
    #include<iomanip>
    using namespace std;
     struct list{
        int ele;
        struct list *next;
        static int length;
    };
    list* create_list(int n);//头插法
    list* create_list2(int n);//尾插法
    int printf_list(list* first);
    list*  find_e(list*first,int e);
    list* find_before(list*first,int e);
    list* insert_e(list* &first,int e,int c);
    list * delete_e(list* &first);
    list* delete_thek(list*first);
    list* insert_thek(list*first,int e);//在第k个位置前插入元素e
    void destroy_list(list*first);
    int  disnum(list*first);
    list* findptail(list*first);//找尾结点
    void update(list*first);//更新函数长度及内容
    int list::length=0;
    int main(){
    
        cout<<"**********功能菜单****************
    ";
        cout<<"1.创建一个节点数为n的单链表*******
    ";
        cout<<"2.***********打印单链表***********
    ";
        cout<<"3.***在值为e的节点前插入值c*******
    ";
        cout<<"4.********删除值为e的节点*********
    ";
        cout<<"5.********删除第k个的节点*********
    ";
        cout<<"6.**********销毁链表**************
    ";
        cout<<"7.*****在第k个位置前插入元素e*****
    ";
        cout<<"8.****************退出************
    ";
        list* first;
        int n,choice,e,c;
        int flag;
        while(cin>>choice&&choice!=6){
            flag=0;
            switch(choice){
                case 1:{first=create_list2(n);break;}
                case 2:{update(first);break;}
                case 3:{insert_e(first,e,c);break;}
                case 4:{delete_e(first);break;}
                case 5:{delete_thek(first);break;}
                case 6:{destroy_list(first);break;}
                case 7:{insert_thek(first,e);break;}
                case 8:{flag=1;break;}
                default:{cout<<"输入不合法,请输入在1~8之间的数字
    ";}
            }
        if(flag==1){break;}
        }
        return 0;
            }
            //头插法创建一个n个节点的单循环链表
    list* create_list(int n){
        list* first=new list;
        first->next=NULL;
        list*p1=first;//标记尾节点
        list* p;
        cout<<"请输入链表中各元素值:"<<endl;
        for(int i=0;i<n;i++){
            p=new list;
            p->next=first;
            first=p;
            cin>>p->ele;
        }
        p1->next=first;
        return first;
    }
         //尾插法创建一个n个节点的单循环链表
    list* create_list2(int n){
        list* pnew,*ptail,*first;
        cout<<"请输入节点数目n:
    ";
        cin>>n;
        cout<<"请输入各元素值:
    ";
        if(n>0) {first=new list;cin>>first->ele;}
        first->next=NULL;
        pnew=ptail=first;
        for(int i=0;i<n-1;i++){
            pnew=new list;
            cin>>pnew->ele;
            ptail->next=pnew;
            ptail=pnew;
        }
        list::length=n;
        ptail->next=first;
        update(first);
        return first;
    }
    //打印整个链表
    int printf_list(list* first){
        list*p=first;
        if (p==NULL) {cout<<"此为一个空表"<<endl;return -1;}
        while(p->next!=first){
            cout<<p->ele<<"  ";
            p=p->next;
        }
        cout<<p->ele<<endl;
        cout<<endl;
        return 0;
    }
    //查找第一个值为e的节点
    list*  find_e(list*first,int e){
        list*p=first;
        for(;p->next!=first;p=p->next){
            if(p->ele==e) return p;//遍历至尾结点未判断,若在之前的位置找到,直接返回相应地址
        }
        //之前没找到,再看是否是尾结点
        if(p->ele==e) return p;
        //若仍未找到
        cout<<"error,"<<e<<" doesn't exist in list"<<endl;
        return  NULL;//返回null是否合适待确定
    }
    //查找第一个值为e的直接前驱
    list* find_before(list*first,int e){
        list* p=first;
        if(p->ele==e){
            while(p->next!=first){
                p=p->next;
            }
            return p;
        }//若e在第一个,则第一个的前驱节点为尾结点
        //若e不在第一个,则遍历链表找e
        while(p->next->ele!=e&&p->next->next!=first){
            p=p->next;//此循环在找到直接前驱或者到倒数第二个节点时终止
        }
        if(p->next->ele==e) return p;//若在倒数第二个之前找到,返回
        //否则,未找到
        else {cout<<"error,"<<e<<" doesn't exist in list"<<endl;return NULL;}
    }
    
    ///在把首节点的前驱作为最后一个节点时,希望插入到第一个元素前--但实际上是插在了认为的前驱----最后一个节点处
    //在第一个值为e的节点前插入值为c的节点
    list* insert_e(list* &first,int e,int c){
        cout<<"选择在e前插入"<<endl;
        cin>>e;
        cout<<"输入待插入的值c"<<endl;
        cin>>c;
        list*p=find_before(first,e);//p即为c的前驱节点
    ///针对119行提出的问题,特此在此加一个if语句处理
    ///因此,要特别注意特殊节点的处理!!!!
        if(p->next==first){
            list* p1=new list;//新节点
            p1->ele=c;
            p1->next=first;
            list *ptail=first;
            while(ptail->next!=first){
                ptail=ptail->next;
            }
            ptail->next=p1;
            first=p1;
            list::length++;
            update(first);
            return first;
    
        }
        list* p1=new list;//新节点
        p1->ele=c;
        p1->next=p->next;
        p->next=p1;
        list::length++;
        update(first);
        return first;
    }
    list* insert_thek(list*first,int e){
        list* p,*q;
        p=first;
        q=NULL;
        int k;
        cout<<"请输入要插入的位置:
    ";
        cin>>k;
        cout<<"请输入要插入的值:
    ";
        cin>>e;
        if(k>list::length+1) cout<<"error,该位置不存在
    ";
        else if(k==list::length+1){//即插在尾部
            p=findptail(first);
            p->next=q;
            q->next=first;
            q->ele=e;
            list::length++;
            update(first);
        }
        else if(k==1){//即插在头部
            p=findptail(first);
            p->next=q;
            q->next=first;
            q->ele=e;
            list::length++;
            update(first);
        }
        else {
            for(int i=0;i<k-2;i++){
                p=p->next;//p为第k个的前驱
            }
            q=new list;
            q->next=p->next;
            p->next=q;
            q->ele=e;
            list::length++;
            update(first);
        }
        return first;
    
    }
    //删除第一个值为e的节点
    list * delete_e(list* &first){
        int e;
        cout<<"输入要删除的值"<<endl;
        cin>>e;
        list* p, *q;
        ///特别注意特殊节点的处理!!!!特别添加一个if来处理删除首节点的情况,如果直接用下面的else中的语句
        ///q为首指针,delete(q)直接把首指针所指的释放了,return (first) 中first指向不存在的空间,故会出错
        if (e==first->ele)
        {
            p=find_before(first,e);//p即为第一个值为e的节点的前驱节点
            q=first;
            first=q->next;///若删除的是第一个,则直接让首指针变为下一个
            delete(q);
            p->next=first;
            list::length--;
            update(first);
            return first;
        }
        else
        {
            p=find_before(first,e);//p即为第一个值为e的节点的前驱节点
            q=p->next;
            p->next=q->next;
            delete(q);
            ///注意不能用delete(p->next);    这样删除的是值为e的节点的后一个节点
            list::length--;
            update(first);
            return first;
        }
    }
    //删除第k个位置上的元素
    list* delete_thek(list*first){
        int k;
        cout<<"请输入要删除的位置:
    ";
        cin>>k;
        list*p,*q;
        p=first;
        if(k>list::length) cout<<"error,该位置不存在
    ";
        else if(k==1) {
                first=first->next;
                list::length--;
                q=findptail(first);
                q->next=first;delete(p);
                list::length--;
                update(first);
    
                return first;   }
        else{   for(int i=0;i<k-2;i++){
                p=p->next;
            }//此时p指向第k个的前驱
        q=p->next;//q指向第k个节点
        p->next=q->next;
        delete(q);
        list::length--;
        update(first);
        }
        return first;
    }
    void destroy_list(list*first){
        list*p=first=first;
        for(;;p=p->next){
            delete(p);
        if(p->next==first) break;
        }
        list::length=0;
        cout<<"链表已销毁
    ";
        delete(first);
    }
    ///另一个问题是,当查找找不到元素e时,会直接结束程序,而不是重新输入,待处理........
    int  disnum(list*first){
        return list::length;
    }
    list* findptail(list*first){
        list*p=first;
        while(p->next!=first){
            p=p->next;
        }
        return p;
    }
    void update(list*first){
        cout<<"新的链表的长度为:"<<disnum(first)<<endl<<"新的链表为:";
        printf_list(first);
    }
    ///还有一个问题是,在插入和删除时,虽然最后修改了首节点,但是只是在该函数内完成,其作用域是代码块,函数调用结束时指针
    ///也被释放,指针并没有被真正修改,而返回的首指针也并没有用到,应该用二级指针或者---指针类型的引用
    
    
  • 相关阅读:
    我的WCF之旅(1):创建一个简单的WCF程序
    网页设计中颜色的搭配
    CSS HACK:全面兼容IE6/IE7/IE8/FF的CSS HACK
    UVa 1326 Jurassic Remains
    UVa 10340 All in All
    UVa 673 Parentheses Balance
    UVa 442 Matrix Chain Multiplication
    UVa 10970 Big Chocolate
    UVa 679 Dropping Balls
    UVa 133 The Dole Queue
  • 原文地址:https://www.cnblogs.com/gao-hongxiang/p/12342430.html
Copyright © 2011-2022 走看看