单链表实现

目录

线性表是数据结构的第一章,而考研和找工作都喜欢考察这方面的内容,因此,我就用C++实现了单链表,以及一些常见的算法题。

本文的具体内容包括:

  1. 单链表的基本操作
  2. 反向输出单链表
  3. 找到两个单链表的第一个公共结点
  4. 对单链表进行排序
  5. 将两个有序的链表合在一起,使之仍然有序

单链表的基本操作

不多说,直接上代码(注意基本操作中参数L的不同):

///初始化一个单链表,申请头结点
void InitList(LinkList *L){
    *L = new LNode;
    if(*L==NULL){
        cout<<"new error"<<endl;
        return;
    }
    (*L)->next = NULL;
}
///释放头结点,将其设为null
void DestroyList(LinkList *L){
    LinkList t ;
    while((*L)!=NULL){
        t = (*L)->next;
        delete (*L);
        (*L) = t;
    }
}
///释放除头结点以外的所有空间
void ClearList(LinkList L){
    LinkList t,q=L;
    L = L->next;
    while(L!=NULL){
        t = L->next;
        delete L;
        L = t;
    }
    q->next = NULL;
}
///获取链表的长度
int Length(LinkList L){
    if(L == NULL)
        return -1;
     int cnt = 0;
     L = L->next;
     while(L!=NULL){
        ++cnt;
        L=L->next;
     }
     return cnt;
}
///返回链表L中第1个与e相等的元素的位置
int locateElem(LinkList L,int e){
    if(L==NULL)
        return -1;
    int index = 0;
    L = L->next;
    while(L!=NULL){
        if(L->data==e){
            return index;
        }
        ++index;
        L = L->next;
    }
    return -1;
}
///获取链表第i个元素的值
bool getElem(LinkList L,int i,LNode &e){
    if(L==NULL or i<0)
        return false;
    int j = 0;
    L = L->next;
    while(L!=NULL){
        if(j==i){
            e.data=L->data;
            e.next=L->next;
            return true;
        }
        ++j;
        L = L->next;
    }
    return false;
}
///在L中第i个位置插入结点e
bool ListInsert(LinkList L,int i,LNode e){
    if(L==NULL)
        return false;
    LinkList p;
    p = L;
    L = L->next;
    int j = 0;
    while(p!=NULL){
        if(j==i){
            LinkList t;
            t = new LNode;
            t->data = e.data;
            t->next = e.next;
            p->next = t;
            t->next = L;
            return true;
        }
        p = L;
        L = L->next;
        ++j;
    }
    return false;
}
///删除第i个元素,并返回该结点
bool ListDelete(LinkList L,int i,LNode &e){
    if(L==NULL)
        return false;
    LinkList p;
    int j = 0;
    p = L;
    L = L->next;
    while(L!=NULL){
        if(i==j){

            e.data = L->data;
            e.next = L->next;

            p->next = L->next;

            delete L;
            return true;
        }
        p = p->next;
        L = L->next;
        ++j;
    }
    return false;

}
///打印单链表L
void PrintList(LinkList L){

    if(L==NULL)
        return;
    L = L->next;
    while(L!=NULL){
        cout<<L->data<<' ';
        L = L->next;
    }
    cout<<" end"<<endl;
}

测试代码:

LinkList L;
    InitList(&L);
    cout<<"the address of the head node is "<<L<<endl;
    LNode e;
    e.data = 124;
    e.next = NULL;

    ListInsert(L,0,e);
    e.data = 132;
    ListInsert(L,0,e);
    e.data = 123;
    ListInsert(L,0,e);
    PrintList(L);

    cout<<"the length of L is "<<Length(L)<<endl;

    cout<<"the location of 132 is "<<locateElem(L,132)<<endl;

    if(getElem(L,1,e)){
        cout<<"the value of location 1 is "<<e.data<<endl;
    }

    if(ListDelete(L,1,e))
        cout<<"the value of deleted element is "<<e.data<<endl;
    else
        cout<<"delete failed"<<endl;

    ClearList(L);
    cout<<L<<endl;
    DestroyList(&L);
    cout<<L<<endl;

运行结果:
这里写图片描述

反向输出单链表

///从尾到头反向输出单链表L
///思路:反向输出很容易就想到栈,
///然后递归的本质就是栈,因此可以用
///递归来实现,先一层层递归到链表尾部,
///当指针为NULL时,返回,返回时输出当前节点的值
void PrintListByReverse(LinkList L){
    if(L==NULL)
        return;
    PrintListByReverse(L->next);
    cout<<L->data<<' ';
}

测试代码:

LinkList L;
    InitList(&L);
    LNode e;
    e.data = 124;
    e.next = NULL;
    ListInsert(L,0,e);
    e.data = 132;
    ListInsert(L,0,e);
    e.data = 123;
    ListInsert(L,0,e);
    e.data = 88;
    ListInsert(L,0,e);
    e.data = 14;
    ListInsert(L,0,e);
    e.data = 26;
    ListInsert(L,0,e);
    cout<<"the origin linklist is:"<<endl;
    PrintList(L);
    cout<<"print list in reverse:"<<endl;
    PrintListByReverse(L->next);
    cout<<"end"<<endl;

运行结果:
这里写图片描述

求两个单链表的公共结点

///找到两个链表的第一个公共结点
/**< 思路:若两个单链表有公共结点,那么他们的逻辑结构
肯定是Y形而不是X形(因为节点的next域只有一个),因此,
可以先计算两个链表的长度,然后先让较长的先移动d
(他们的长度差)个节点这样他们就会同时到达公共结点,
只需比较两个指针就可以了 */
bool FindCommonNode(LinkList La,LinkList Lb,LNode &e){
    if(La==NULL || Lb==NULL)
        return false;
    int la,lb;///La/Lb 的长度
    la = Length(La);
    lb = Length(Lb);
    int d = la-lb;
    int i = 0;
    La = La->next;
    Lb = Lb->next;
    if(d>0){
        while(La!=NULL){
            if(i==d){
                break;
            }
            ++i;
            La = La->next;
        }
    }
    else{
        d=-d;
        while(Lb!=NULL){
            if(i==d){
                break;
            }
            ++i;
            Lb = Lb->next;
        }
    }
    while(La!=NULL && Lb!=NULL){
        if(La == Lb){
            e.data = La->data;
            e.next = La->next;
            return true;
        }
        La = La->next;
        Lb = Lb->next;
    }
    return false;
}

测试代码:

LinkList L;
    InitList(&L);
    LNode e;
    e.data = 124;
    e.next = NULL;
    ListInsert(L,0,e);
    e.data = 132;
    ListInsert(L,0,e);



    LinkList myList;
    InitList(&myList);
    e.data = 83;
    ListInsert(myList,0,e);
    e.data = 19;
    ListInsert(myList,0,e);
    e.data = 46;
    ListInsert(myList,0,e);
    ConcatList(myList,L);
    cout<<"list 1 is:"<<endl;
    PrintList(myList);

    LinkList hisList;
    InitList(&hisList);
    e.data = 547;
    ListInsert(hisList,0,e);
    e.data = 78;
    ListInsert(hisList,0,e);
    ConcatList(hisList,L);
    cout<<"list 2 is:"<<endl;
    PrintList(hisList);

    if(FindCommonNode(myList,hisList,e))
        cout<<"the first common node is "<<e.data<<endl;

运行结果:
这里写图片描述

单链表排序

///对单链表进行排序
/**< 可使用插入排序,每次从后面选择一个结点,
在前面有序的序列选择一个合适的位置插入 */
void SortList(LinkList L){
    if(L==NULL)
        return;
    LinkList q,r,s,x;
    r = L;
    x = L;
    L=L->next;
    bool flag;
    while(L!=NULL){
        ///在前面找到合适的位置插入
        s = r;
        q = r->next;
        flag = false;
        while(q!=NULL && q!=L){
            ///找到第一个比当前结点大的结点
            if(q->data > L->data){
                flag = true;
                x->next = L->next;
                L->next = q;
                s->next = L;
                //PrintList(r);
                break;
            }
            s = s->next;
            q = q->next;
        }
        if(flag!= true)
            x=x->next;
        L=x->next;
    }

}

测试代码:

LinkList L;
    InitList(&L);
    LNode e;
    e.data = 124;
    e.next = NULL;
    ListInsert(L,0,e);
    e.data = 132;
    ListInsert(L,0,e);

    LinkList myList;
    InitList(&myList);
    e.data = 83;
    ListInsert(myList,0,e);
    e.data = 19;
    ListInsert(myList,0,e);
    e.data = 46;
    ListInsert(myList,0,e);
    ConcatList(myList,L);
    cout<<"before sort:"<<endl;
    PrintList(myList);
    SortList(myList);
    cout<<"after sort:"<<endl;
    PrintList(myList);

运行结果:
这里写图片描述

合并有序单链表

///合并有序单链表La、Lb,放到La里面去,并且合并后的链表仍然有序
void MergeList(LinkList La,LinkList Lb){
    LinkList pa = La->next,pb = Lb->next,t;
    LNode *r;
    La->next  = NULL; ///La 作为结果链表的指针
    t = La;
    while(pa != NULL && pb != NULL){
        if(pa->data > pb->data){
            r = pb->next; ///r 暂存pb的后继结点
            ///在La插入
            pb->next = La->next;
            La->next = pb;
            ///恢复pb为下一个待比较结点
            pb = r;
            La = La->next;
        }
        else{
            r = pa->next; ///r 暂存pb的后继结点
            ///在La插入
            pa->next = La->next;
            La->next = pa;
            ///恢复pb为下一个待比较结点
            pa = r;
            La = La->next;
        }
        //PrintList(t);

    }
    if(pa!=NULL)
        La->next = pa;
    if(pb!=NULL)
        La->next = pb;
    delete Lb;
}

测试代码:

 LNode e;
    LinkList List1;
    InitList(&List1);
    e.data = 24;
    ListInsert(List1,0,e);
    e.data = 68;
    ListInsert(List1,0,e);
    e.data = 35;
    ListInsert(List1,0,e);
    e.data = 123;
    ListInsert(List1,0,e);
    e.data = 77;
    ListInsert(List1,0,e);
    e.data = 15;
    ListInsert(List1,0,e);
    SortList(List1);


    LinkList List2;
    InitList(&List2);
    e.data = 23;
    ListInsert(List2,0,e);
    e.data = 46;
    ListInsert(List2,0,e);
    e.data = 98;
    ListInsert(List2,0,e);
    e.data = 143;
    ListInsert(List2,0,e);
    e.data = 18;
    ListInsert(List2,0,e);
    e.data = 85;
    ListInsert(List2,0,e);
    SortList(List2);
    cout<<"list 1 is :"<<endl;
    PrintList(List1);
    cout<<"list 2 is :"<<endl;
    PrintList(List2);
    MergeList(List1,List2);
    cout<<"after merge:"<<endl;
    PrintList(List1);

运行结果:
这里写图片描述

总结

虽然说单链表逻辑比较简单,但是涉及指针操作,很容易出错,我建议在纸上画图来编写代码,这样思路比较清晰。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值