数据结构学习之路-第二章:带头结点的线性链表

【 声明:版权所有,转载请标明出处,请勿用于商业用途。  联系信箱:libin493073668@sina.com】


前言:

终于讲到书中的最后一个链表了,前面我们一步一步的介绍了顺序表,单链表,静态单链表,循环链表,双向链表,这次总算是进入了最后的链表学习了,那就是带头结点的线性链表,按照书本所说,这个是比前面几个更具有实用意义的链表。那么我也不多说了,让我们开始进入学习吧。


注:

本文仅代表博主本人的一些浅显的见解,欢迎大家评论学习,共同创造出一个良好的环境

对于一些问题,博主会尽量为大家解答,但是如果有疑问没有及时回答的,也希望其他热心人心帮忙解决,鄙人不胜感激


带头结点的线性链表


1.存储结构

在这里我们除了像之前的链表那样定义一个结点类型之外,我们还需要定义一个链表类型,结点类型还是记录着结点的数据data与其直接后继的指针next,而链表类型则是记录着整个链表的头指针head,尾指针tail和长度len

typedef struct LNode      //结点类型
{
    ElemType data;
    struct LNode *next;
} LNode,*Link,*Position;

typedef struct           //链表类型
{
    Link head,tail;      //分别指向线性链表中的头结点和最后一个结点
    int len;             //指示线性链表中数据元素的个数
} LinkList;

2.基本操作

以下给出的都是书本上定义的基本操作,相信在之前链表的学习中,大家对于链表的指针操作已经不会陌生了,通过所添加的注释应该能够很好的理解每个操作的原理,如果还有不懂的,也欢迎大家一起和我探讨。

Status MakeNode(Link *p,ElemType e)
{
//     操作结果:分配由p指向的值为e的结点,并返回OK;若分配失败。则返回ERROR
    (*p) = (Link)malloc(sizeof(LNode));  //分配新结点
    if(!(*p)) return ERROR;              //分配失败
    (*p)->data = e;
    return OK;
}

void FreeNode(Link *p)
{
//     操作结果:释放p所指结点
    free(*p);
    (*p) = NULL;
}

Status InitList(LinkList *L)
{
//     操作结果:构造一个空的线性链表
    Link p;
    p = (Link)malloc(sizeof(LNode));  //生成头结点
    if(p)
    {
        p->next = NULL;
        (*L).head = (*L).tail = p;
        (*L).len = 0;
        return OK;
    }
    else
        return ERROR;
}

Status ClearList(LinkList *L)
{
//     操作结果:将线性链表L重置为空表,并释放原链表的结点空间
    Link p,q;
    if((*L).head!=(*L).tail)      //不是空表
    {
        p = q = (*L).head->next;  //指向第一个结点
        (*L).head->next = NULL;
        while(p!=(*L).tail)       //释放所有结点
        {
            p = q->next;
            free(q);
            q = p;
        }
        free(q);
        (*L).tail = (*L).head;
        (*L).len = 0;
    }
    return OK;
}

Status DestroyList(LinkList *L)
{
//     操作结果:销毁线性链表L,L不再存在
    ClearList(L);          //清空链表
    FreeNode(&(*L).head);  //释放头结点
    (*L).tail = NULL;
    (*L).len = 0;
    return OK;
}

Status InsFirst(LinkList *L,Link h,Link s)   //形参增加L,因为需修改L
{
//     操作结果:h指向L的一个结点,把h当做头结点,将s所指结点插入在第一个结点之前
    s->next = h->next;
    h->next = s;
    if(h==(*L).tail)         //h指向尾结点
        (*L).tail = h->next; //修改尾指针
    (*L).len++;
    return OK;
}

Status DelFirst(LinkList *L,Link h,Link *q) //形参增加L,因为需修改L
{
//     操作结果:h指向L的一个结点,把h当做头结点,删除链表中的第一个结点并以q返回。若链表为空(h指向尾结点),q=NULL,返回FALSE
    *q = h->next;
    if(*q)                     //链表非空
    {
        h->next = (*q)->next;
        if(!h->next)           //删除尾结点
            (*L).tail = h;     //修改尾指针
        (*L).len--;
        return OK;
    }
    else
        return FALSE;          //链表空

}

Status Append(LinkList *L,Link s)
{
//     操作结果:将指针s(s->data为第一个数据元素)所指(彼此以指针相链,以NULL结尾)的一串结点链接在线性链表L的最后一个结点之后,并改变链表L的尾指针指向新的尾结点
    int i=1;
    (*L).tail->next = s;  //s接到L的尾部
    while(s->next)        //计算s的长度
    {
        i++;
        s = s->next;
    }
    (*L).tail = s;        //L的尾指针变成s的尾指针
    (*L).len+=i;          //增加长度
    return OK;
}

Position PriorPos(LinkList L,Link p)
{
//     操作结果:已知p指向线性链表L中的一个结点,返回p所指结点的直接前驱的位置,若无前驱,则返回NULL
    Link q;
    q = L.head->next;
    if(q==p) return NULL;   //无前驱
    while(q->next!=p)       //q不是p的直接前驱
        q = q->next;
    return q;
}

Status Remove(LinkList *L,Link *q)
{
//     操作结果:删除线性链表L中的尾结点并以q返回,改变链表L的尾指针指向新的尾结点
    Link p = (*L).head;
    if((*L).len==0)          //空表
    {
        *q = NULL;
        return FALSE;
    }
    while(p->next!=(*L).tail) //寻找尾结点
        p = p->next;
    *q = (*L).tail;           //返回原来的尾结点
    p->next = NULL;           //尾结点变成NULL
    (*L).tail = p;            //修改尾结点地址
    (*L).len--;
    return OK;
}

Status InsBefore(LinkList *L,Link *p,Link s)
{
//     操作结果:已知p指向线性链表L中的一个结点,将s所指结点插入在p所指结点之前,并修改指针p指向新插入的结点
    Link q;
    q = PriorPos(*L,*p); //q是p的前驱
    if(!q)               //p无前驱
        q = (*L).head;
    s->next = *p;        //插入操作
    q->next = s;
    *p = s;
    (*L).len++;
    return OK;
}

Status InsAfter(LinkList *L,Link *p,Link s)
{
//     操作结果:已知p指向线性链表L中的一个结点,将s所指结点插入在p所指结点之后,并修改指针p指向新插入的结点
    if(*p==(*L).tail)     //修改尾指针
        (*L).tail = s;
    s->next = (*p)->next; //插入操作
    (*p)->next = s;
    *p = s;
    (*L).len++;
    return OK;
}

Status SetCurElem(Link p,ElemType e)
{
//     操作结果:已知p指向线性链表中的一个结点,用e更新p所指结点中数据元素的值
    p->data = e;
    return OK;
}

ElemType GetCurElem(Link p)
{
//     操作结果:已知p指向线性链表中的一个结点,返回p所指结点中数据元素的值
    return p->data;
}

Status ListEmpty(LinkList L)
{
//     操作结果:若线性链表L为空表,则返回TRUE,否则返回FALSE
    return L.len==0;
}

int ListLength(LinkList L)
{
//     操作结果:返回线性链表L中元素个数
    return L.len;
}

Position GetHead(LinkList L)
{
//     操作结果:返回线性链表L中头结点的位置
    return L.head;
}

Position GetLast(LinkList L)
{
//     操作结果:返回线性链表L中最后一个结点的位置
    return L.tail;
}

Position NextPos(Link p)
{
//     操作结果:已知p指向线性链表L中的一个结点,返回p所指结点的直接后继的位置
//     若无后继,则返回NULL
    return p->next;
}

Status LocatePos(LinkList L,int i,Link *p)
{
//     操作结果:返回p指示线性链表L中第i个结点的位置,并返回OK,i值不合法时返回ERROR
//     i=0为头结点
    if(i<0 || i>L.len) return ERROR;
    *p = L.head;
    for(int j = 1; j<=i; j++)
        *p=(*p)->next;
    return OK;
}

Position LocateElem(LinkList L,ElemType e,Status (*compare)(ElemType,ElemType))
{
//     操作结果:返回线性链表L中第1个与e满足函数compare()判定关系的元素的位置,
//     若不存在这样的元素,则返回NULL
    Link p;
    int i = 1;
    p = L.head;
    do
    {
        p = p->next;
    }
    while(p && !compare(p->data,e));
    return p;
}

Status ListTraverse(LinkList L,void(*visit)(ElemType))
{
//     操作结果:依次对L的每个数据元素调用函数visit()。一旦visit()失败,则操作失败
    Link p = L.head->next;
    for(int i = 1; i<=L.len; i++)
    {
        visit(p->data);
        p = p->next;
    }
    printf("\n");
    return OK;

}

Status OrderInsert(LinkList *L,ElemType e,int (*comp)(ElemType,ElemType))
{
//     操作结果:已知L为有序线性链表,将元素e按非降序插入在L中。(用于一元多项式) */
    Link o,p,q;
    q = (*L).head;
    p = q->next;
    while(p!=NULL && comp(p->data,e)<0) //p不是表尾且元素值小于e
    {
        q = p;
        p = p->next;
    }
    o = (Link)malloc(sizeof(LNode));    //生成新结点
    o->data = e;   //赋值
    q->next = o;   //插入
    o->next = p;
    (*L).len++;    //表长增加
    if(!p)         //插入表尾
        (*L).tail = o;   //修改尾结点
    return OK;
}

Status LocateElemP(LinkList L,ElemType e,Position *q,int(*compare)(ElemType,ElemType))
{
//     操作结果:若升序链表L中存在与e满足判定函数compare()取值为0的元素,
//     则q指示L中第一个值为e的结点的位置,并返回TRUE;
//     否则q指示第一个与e满足判定函数 compare()取值>0的元素的前驱的位置。并返回FALSE。(用于一元多项式)
    Link p=L.head,pp;
    do
    {
        pp = p;
        p = p->next;
    }
    while(p && compare(p->data,e)<0);  //找到第一个大于等于e的位置
    if(!p || compare(p->data,e)>0)     //到表尾或者找到的位置的值并不相等
    {
        *q = pp;
        return FALSE;
    }
    else           //找到相等
    {
        *q = p;
        return TRUE;
    }
}


3.插入与合并

这正是书中的算法2.20与算法2.21,也是老知识点了,对于归并线性表的原理想必大家也早就烂熟于胸了吧。

Status ListInsert_L(LinkList *L,int i,ElemType e)
{
//     操作结果:在带头结点的单链线性表L的第i个元素之前插入元素e
    Link h,s;
    if(!LocatePos(*L,i-1,&h)) return ERROR;   //i值不合法
    if(!MakeNode(&s,e)) return ERROR;         //结点分配失败
    InsFirst(L,h,s);     //对于从第i个结点开始的链表,第i-1个结点是它的头结点
    return OK;
}

Status MergeList_L(LinkList La,LinkList Lb,LinkList *Lc,int(*compare)(ElemType,ElemType))
{
//     初始条件:已知单链线性表La和Lb的元素按值非递减排列。
//     操作结果:归并La和Lb得到新的单链,线性表Lc,Lc的元素也按值非递减排列。(不改变La、Lb)
    Link ha,hb,pa,pb,q;
    ElemType a,b;
    if(!InitList(Lc)) return ERROR;        //存储空间分配失败
    ha = GetHead(La);   //ha和hb分别指向La和Lb的头结点
    hb = GetHead(Lb);
    pa = NextPos(ha);   //pa和pb分别指向La和Lb的第一个结点
    pb = NextPos(hb);
    while(!ListEmpty(La)&&!ListEmpty(Lb))  //La和Lb均非空
    {
        a = GetCurElem(pa);                //a和b为两表中当前比较元素
        b = GetCurElem(pb);
        if(compare(a,b)<=0)
        {
            DelFirst(&La,ha,&q);          //删除La的头结点并以q返回
            InsFirst(Lc,(*Lc).tail,q);    //把q插入作为Lc的尾结点
            pa = NextPos(ha);
        }
        else
        {
            DelFirst(&Lb,hb,&q);
            InsFirst(Lc,(*Lc).tail,q);
            pb = NextPos(hb);
        }
    }
    if(pa) Append(Lc,pa);
    else Append(Lc,pb);
    FreeNode(&ha);
    FreeNode(&hb);
    return OK;
}

4.具体测试

#include "my.h"

typedef int ElemType;
typedef int Status;

typedef struct LNode      //结点类型
{
    ElemType data;
    struct LNode *next;
} LNode,*Link,*Position;

typedef struct           //链表类型
{
    Link head,tail;      //分别指向线性链表中的头结点和最后一个结点
    int len;             //指示线性链表中数据元素的个数
} LinkList;

Status MakeNode(Link *p,ElemType e)
{
//     操作结果:分配由p指向的值为e的结点,并返回OK;若分配失败。则返回ERROR
    (*p) = (Link)malloc(sizeof(LNode));  //分配新结点
    if(!(*p)) return ERROR;              //分配失败
    (*p)->data = e;
    return OK;
}

void FreeNode(Link *p)
{
//     操作结果:释放p所指结点
    free(*p);
    (*p) = NULL;
}

Status InitList(LinkList *L)
{
//     操作结果:构造一个空的线性链表
    Link p;
    p = (Link)malloc(sizeof(LNode));  //生成头结点
    if(p)
    {
        p->next = NULL;
        (*L).head = (*L).tail = p;
        (*L).len = 0;
        return OK;
    }
    else
        return ERROR;
}

Status ClearList(LinkList *L)
{
//     操作结果:将线性链表L重置为空表,并释放原链表的结点空间
    Link p,q;
    if((*L).head!=(*L).tail)      //不是空表
    {
        p = q = (*L).head->next;  //指向第一个结点
        (*L).head->next = NULL;
        while(p!=(*L).tail)       //释放所有结点
        {
            p = q->next;
            free(q);
            q = p;
        }
        free(q);
        (*L).tail = (*L).head;
        (*L).len = 0;
    }
    return OK;
}

Status DestroyList(LinkList *L)
{
//     操作结果:销毁线性链表L,L不再存在
    ClearList(L);          //清空链表
    FreeNode(&(*L).head);  //释放头结点
    (*L).tail = NULL;
    (*L).len = 0;
    return OK;
}

Status InsFirst(LinkList *L,Link h,Link s)   //形参增加L,因为需修改L
{
//     操作结果:h指向L的一个结点,把h当做头结点,将s所指结点插入在第一个结点之前
    s->next = h->next;
    h->next = s;
    if(h==(*L).tail)         //h指向尾结点
        (*L).tail = h->next; //修改尾指针
    (*L).len++;
    return OK;
}

Status DelFirst(LinkList *L,Link h,Link *q) //形参增加L,因为需修改L
{
//     操作结果:h指向L的一个结点,把h当做头结点,删除链表中的第一个结点并以q返回。若链表为空(h指向尾结点),q=NULL,返回FALSE
    *q = h->next;
    if(*q)                     //链表非空
    {
        h->next = (*q)->next;
        if(!h->next)           //删除尾结点
            (*L).tail = h;     //修改尾指针
        (*L).len--;
        return OK;
    }
    else
        return FALSE;          //链表空

}

Status Append(LinkList *L,Link s)
{
//     操作结果:将指针s(s->data为第一个数据元素)所指(彼此以指针相链,以NULL结尾)的一串结点链接在线性链表L的最后一个结点之后,并改变链表L的尾指针指向新的尾结点
    int i=1;
    (*L).tail->next = s;  //s接到L的尾部
    while(s->next)        //计算s的长度
    {
        i++;
        s = s->next;
    }
    (*L).tail = s;        //L的尾指针变成s的尾指针
    (*L).len+=i;          //增加长度
    return OK;
}

Position PriorPos(LinkList L,Link p)
{
//     操作结果:已知p指向线性链表L中的一个结点,返回p所指结点的直接前驱的位置,若无前驱,则返回NULL
    Link q;
    q = L.head->next;
    if(q==p) return NULL;   //无前驱
    while(q->next!=p)       //q不是p的直接前驱
        q = q->next;
    return q;
}

Status Remove(LinkList *L,Link *q)
{
//     操作结果:删除线性链表L中的尾结点并以q返回,改变链表L的尾指针指向新的尾结点
    Link p = (*L).head;
    if((*L).len==0)          //空表
    {
        *q = NULL;
        return FALSE;
    }
    while(p->next!=(*L).tail) //寻找尾结点
        p = p->next;
    *q = (*L).tail;           //返回原来的尾结点
    p->next = NULL;           //尾结点变成NULL
    (*L).tail = p;            //修改尾结点地址
    (*L).len--;
    return OK;
}

Status InsBefore(LinkList *L,Link *p,Link s)
{
//     操作结果:已知p指向线性链表L中的一个结点,将s所指结点插入在p所指结点之前,并修改指针p指向新插入的结点
    Link q;
    q = PriorPos(*L,*p); //q是p的前驱
    if(!q)               //p无前驱
        q = (*L).head;
    s->next = *p;        //插入操作
    q->next = s;
    *p = s;
    (*L).len++;
    return OK;
}

Status InsAfter(LinkList *L,Link *p,Link s)
{
//     操作结果:已知p指向线性链表L中的一个结点,将s所指结点插入在p所指结点之后,并修改指针p指向新插入的结点
    if(*p==(*L).tail)     //修改尾指针
        (*L).tail = s;
    s->next = (*p)->next; //插入操作
    (*p)->next = s;
    *p = s;
    (*L).len++;
    return OK;
}

Status SetCurElem(Link p,ElemType e)
{
//     操作结果:已知p指向线性链表中的一个结点,用e更新p所指结点中数据元素的值
    p->data = e;
    return OK;
}

ElemType GetCurElem(Link p)
{
//     操作结果:已知p指向线性链表中的一个结点,返回p所指结点中数据元素的值
    return p->data;
}

Status ListEmpty(LinkList L)
{
//     操作结果:若线性链表L为空表,则返回TRUE,否则返回FALSE
    return L.len==0;
}

int ListLength(LinkList L)
{
//     操作结果:返回线性链表L中元素个数
    return L.len;
}

Position GetHead(LinkList L)
{
//     操作结果:返回线性链表L中头结点的位置
    return L.head;
}

Position GetLast(LinkList L)
{
//     操作结果:返回线性链表L中最后一个结点的位置
    return L.tail;
}

Position NextPos(Link p)
{
//     操作结果:已知p指向线性链表L中的一个结点,返回p所指结点的直接后继的位置
//     若无后继,则返回NULL
    return p->next;
}

Status LocatePos(LinkList L,int i,Link *p)
{
//     操作结果:返回p指示线性链表L中第i个结点的位置,并返回OK,i值不合法时返回ERROR
//     i=0为头结点
    if(i<0 || i>L.len) return ERROR;
    *p = L.head;
    for(int j = 1; j<=i; j++)
        *p=(*p)->next;
    return OK;
}

Position LocateElem(LinkList L,ElemType e,Status (*compare)(ElemType,ElemType))
{
//     操作结果:返回线性链表L中第1个与e满足函数compare()判定关系的元素的位置,
//     若不存在这样的元素,则返回NULL
    Link p;
    int i = 1;
    p = L.head;
    do
    {
        p = p->next;
    }
    while(p && !compare(p->data,e));
    return p;
}

Status ListTraverse(LinkList L,void(*visit)(ElemType))
{
//     操作结果:依次对L的每个数据元素调用函数visit()。一旦visit()失败,则操作失败
    Link p = L.head->next;
    for(int i = 1; i<=L.len; i++)
    {
        visit(p->data);
        p = p->next;
    }
    printf("\n");
    return OK;

}

Status OrderInsert(LinkList *L,ElemType e,int (*comp)(ElemType,ElemType))
{
//     操作结果:已知L为有序线性链表,将元素e按非降序插入在L中。(用于一元多项式) */
    Link o,p,q;
    q = (*L).head;
    p = q->next;
    while(p!=NULL && comp(p->data,e)<0) //p不是表尾且元素值小于e
    {
        q = p;
        p = p->next;
    }
    o = (Link)malloc(sizeof(LNode));    //生成新结点
    o->data = e;   //赋值
    q->next = o;   //插入
    o->next = p;
    (*L).len++;    //表长增加
    if(!p)         //插入表尾
        (*L).tail = o;   //修改尾结点
    return OK;
}

Status LocateElemP(LinkList L,ElemType e,Position *q,int(*compare)(ElemType,ElemType))
{
//     操作结果:若升序链表L中存在与e满足判定函数compare()取值为0的元素,
//     则q指示L中第一个值为e的结点的位置,并返回TRUE;
//     否则q指示第一个与e满足判定函数 compare()取值>0的元素的前驱的位置。并返回FALSE。(用于一元多项式)
    Link p=L.head,pp;
    do
    {
        pp = p;
        p = p->next;
    }
    while(p && compare(p->data,e)<0);  //找到第一个大于等于e的位置
    if(!p || compare(p->data,e)>0)     //到表尾或者找到的位置的值并不相等
    {
        *q = pp;
        return FALSE;
    }
    else           //找到相等
    {
        *q = p;
        return TRUE;
    }
}

Status ListInsert_L(LinkList *L,int i,ElemType e)
{
//     操作结果:在带头结点的单链线性表L的第i个元素之前插入元素e
    Link h,s;
    if(!LocatePos(*L,i-1,&h)) return ERROR;   //i值不合法
    if(!MakeNode(&s,e)) return ERROR;         //结点分配失败
    InsFirst(L,h,s);     //对于从第i个结点开始的链表,第i-1个结点是它的头结点
    return OK;
}

Status MergeList_L(LinkList La,LinkList Lb,LinkList *Lc,int(*compare)(ElemType,ElemType))
{
//     初始条件:已知单链线性表La和Lb的元素按值非递减排列。
//     操作结果:归并La和Lb得到新的单链,线性表Lc,Lc的元素也按值非递减排列。(不改变La、Lb)
    Link ha,hb,pa,pb,q;
    ElemType a,b;
    if(!InitList(Lc)) return ERROR;        //存储空间分配失败
    ha = GetHead(La);   //ha和hb分别指向La和Lb的头结点
    hb = GetHead(Lb);
    pa = NextPos(ha);   //pa和pb分别指向La和Lb的第一个结点
    pb = NextPos(hb);
    while(!ListEmpty(La)&&!ListEmpty(Lb))  //La和Lb均非空
    {
        a = GetCurElem(pa);                //a和b为两表中当前比较元素
        b = GetCurElem(pb);
        if(compare(a,b)<=0)
        {
            DelFirst(&La,ha,&q);          //删除La的头结点并以q返回
            InsFirst(Lc,(*Lc).tail,q);    //把q插入作为Lc的尾结点
            pa = NextPos(ha);
        }
        else
        {
            DelFirst(&Lb,hb,&q);
            InsFirst(Lc,(*Lc).tail,q);
            pb = NextPos(hb);
        }
    }
    if(pa) Append(Lc,pa);
    else Append(Lc,pb);
    FreeNode(&ha);
    FreeNode(&hb);
    return OK;
}

Status compare(ElemType c1,ElemType c2)
{
    return c1==c2;
}

int cmp(ElemType a,ElemType b)
{
    if(a==b)
        return 0;
    else if(a<b)
        return -1;
    return 1;
}

void visit(ElemType c)
{
    printf("%d ",c);
}

int comp(ElemType c1,ElemType c2)
{
    return c1-c2;
}

int main()
{
    Link p,h;
    LinkList L;
    Status i;
    int j,k;
    i=InitList(&L);
    if(!i)                      //初始化空的线性表L不成功
        exit(FALSE);            //退出程序运行
    for(j=1; j<=2; j++)
    {
        MakeNode(&p,j);         //生成由p指向、值为j的结点
        InsFirst(&L,L.tail,p);  //插在表尾
    }
    OrderInsert(&L,0,cmp);      //按升序插在有序表头
    for(j=0; j<=3; j++)
    {
        i=LocateElemP(L,j,&p,cmp);
        if(i)
            printf("链表中有值为%d的元素。\n",p->data);
        else
            printf("链表中没有值为%d的元素。\n",j);
    }
    printf("输出链表:");
    ListTraverse(L,visit);          //输出L
    for(j=1; j<=4; j++)
    {
        printf("删除表头结点:");
        DelFirst(&L,L.head,&p);     //删除L的首结点,并以p返回
        if(p)
            printf("%d\n",GetCurElem(p));
        else
            printf("表空,无法删除 p=%u\n",p);
    }
    printf("L中结点个数=%d L是否空 %d(1:空 0:否)\n",ListLength(L),ListEmpty(L));
    MakeNode(&p,10);
    p->next=NULL;        //尾结点
    for(j=4; j>=1; j--)
    {
        MakeNode(&h,j*2);
        h->next=p;
        p=h;
    }                         //h指向一串5个结点,其值依次是2 4 6 8 10
    Append(&L,h);             //把结点h链接在线性链表L的最后一个结点之后
    OrderInsert(&L,12,cmp);   //按升序插在有序表尾头
    OrderInsert(&L,7,cmp);    //按升序插在有序表中间
    printf("输出链表:");
    ListTraverse(L,visit);    //输出L
    for(j=1; j<=2; j++)
    {
        p=LocateElem(L,j*5,compare);
        if(p)
            printf("L中存在值为%d的结点。\n",j*5);
        else
            printf("L中不存在值为%d的结点。\n",j*5);
    }
    for(j=1; j<=2; j++)
    {
        LocatePos(L,j,&p);     //p指向L的第j个结点
        h=PriorPos(L,p);       //h指向p的前驱
        if(h)
            printf("%d的前驱是%d。\n",p->data,h->data);
        else
            printf("%d没前驱。\n",p->data);
    }
    k=ListLength(L);
    for(j=k-1; j<=k; j++)
    {
        LocatePos(L,j,&p);   //p指向L的第j个结点
        h=NextPos(p);        //h指向p的后继
        if(h)
            printf("%d的后继是%d。\n",p->data,h->data);
        else
            printf("%d没后继。\n",p->data);
    }
    printf("L中结点个数=%d L是否空 %d(1:空 0:否)\n",ListLength(L),ListEmpty(L));
    p=GetLast(L);        //p指向最后一个结点
    SetCurElem(p,15);    //将最后一个结点的值变为15
    printf("第1个元素为%d 最后1个元素为%d\n",GetCurElem(GetHead(L)->next),GetCurElem(p));
    MakeNode(&h,10);
    InsBefore(&L,&p,h);  //将10插到尾结点之前,p指向新结点
    p=p->next;           //p恢复为尾结点
    MakeNode(&h,20);
    InsAfter(&L,&p,h);   //将20插到尾结点之后
    k=ListLength(L);
    printf("依次删除表尾结点并输出其值:");
    for(j=0; j<=k; j++)
    {
        i=Remove(&L,&p);
        if(!i)           //删除不成功
            printf("删除不成功 p=%u\n",p);
        else
            printf("%d ",p->data);
    }
    MakeNode(&p,29);     //重建具有1个结点(29)的链表
    InsFirst(&L,L.head,p);
    DestroyList(&L);     //销毁线性链表L
    printf("销毁线性链表L之后: L.head=%u L.tail=%u L.len=%d\n",L.head,L.tail,L.len);

//    归并操作
    LinkList La,Lb,Lc;
    InitList(&La);
    for(j=1; j<=5; j++)
        ListInsert_L(&La,j,j);    //顺序插入 1 2 3 4 5
    printf("La=");
    ListTraverse(La,visit);
    InitList(&Lb);
    for(j=1; j<=5; j++)
        ListInsert_L(&Lb,j,2*j);  //顺序插入 2 4 6 8 10
    printf("Lb=");
    ListTraverse(Lb,visit);
    InitList(&Lc);
    MergeList_L(La,Lb,&Lc,comp);  //归并La和Lb,产生Lc
    printf("Lc=");
    ListTraverse(Lc,visit);
    DestroyList(&Lc);

    return 0;
}

总结:

基本的链表学习到此应该就算是告一段落了,不知道大家是否有所收获呢?

下一次我会介绍以书本最后的一元多项式实现,然后便结束我们的第二章的学习。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值