链表家族(3)——双向循环链表

总述

最后一位介绍的成员。
(附上单链表描述:http://blog.csdn.net/lliangw/article/details/50914976
(附上双向链表描述:http://blog.csdn.net/lliangw/article/details/50915313

概述

最灵活常用的链表。

实现

总体来说比较简单。
因为我们创建链表是构建了一个表头空结点,所以只要在一开始将其两个指针指向自己就行了。
这里引用一些非常实用的子函数。

创建一个空的双向循环链表

int InitList_L(LinkList &L)
{
    if(L)DestroyList_L(L);                //如果链表已存在,先销毁 
    L = (LinkList) malloc (sizeof (LNode));
    if (!L) return 1;                    // 存储分配失败
    L->num = MAXNUM; L->score = MAXSCORE;//表头空结点赋特殊值 
    memset(L->name,0,sizeof(L->name));
    L->prior = L;               // 双向循环链表只有表头空节点时,前向和后向 
    L->next = L;                         // 指针都是指向自己的 
    return 0;
}

测链表长度

int ListLength_L(LinkList L)
{
    int i;
    LinkList p = L->next;
    for(i=0,p=L;p->next!=L;p=p->next,i++);//空循环,只计数 ;
    return i;
} 

销毁链表

void DestroyList_L(LinkList &L)
{
    LinkList p = L->prior->prior;
    for(L->prior==NULL;p;p=p->prior)//从后向前逐个销毁 
        free(p->next);
    free(L);
}

回第pos个元素的地址

LinkList ListGetElem(LinkList L, int pos)
{
    LinkList e = NULL;            //定义结点指针
    int len = ListLength_L(L);
    if(pos<0 || pos>len)return 0;  //位置不合法 ,思考为什么0也合法? 
    e = L; 
    for(int i=0;i<pos;i++,e=e->next);  //空循环体,只是把e定位到pos-1 
    return e;
}

顺序输出链表

void PrintList_L(LinkList L)
{
    LinkList p = L->next;
    for(;p!=L;p=p->next)
        cout << p->num << ' ' << p->name << ' ' << p->score << endl;
}

在链表中t指向的元素之后插入元素

int ListInsert_L(LinkList t, LNode e)
{
    if(!t)return 1;//获取地址失败,返回 
    LinkList p = (LinkList) malloc (sizeof (LNode));
    if (!p) return 1; // 存储分配失败
    *p = e;             //结构体是可以直接赋值的 
    p->next = t->next;  t->next = p;  //后向指针链接修改 
    p->next->prior = p; p->prior = t; //前向指针链接修改
    return 0;
}

构造带数据的链表

int CreateList_L(LinkList &L)
{
    if(L)DestroyList_L(L);//如果链表已存在,先销毁
    InitList_L(L);      //初始化链表 
    int i,n;
    cin >> n;
    while(n--)
    {
        LinkList p = (LinkList) malloc (sizeof (LNode));
        if (!p) return 1; // 存储分配失败
        cin >> p->num >> p->name >> p->score;
        LinkList t = L->prior;
        p->next = t->next;  t->next = p;  //后向指针链接修改 
        p->next->prior = p; p->prior = t; //前向指针链接修改
    }
}

删除p指向的元素

int ListDelete_L(LinkList p)
{
    if (p->num==MAXNUM || !p) return 1;//判定删除位置是否合法,表头能删吗? 
    p->prior->next = p->next;    //后向指针链接修改
    p->next->prior = p->prior;  //前向指针链接修改
    free(p);            //销毁该元素 
    return 0;
} 

学号相等判定函数

int CmpNum(LinkList pa, LinkList pb)
{
    return pa->num == pb->num;
}

查找并返回地址,未找到返回表头空结点地址

利用外部函数判定

LinkList LocateElem_L(LinkList L, LNode e, int (*cmp)(LinkList,LinkList))
{
    LinkList p=L->next;  //p是查找指针 
    for(;p!=L;p=p->next)
        if(cmp(p,&e))break;//循环查找,找到推出循环 
    return p;               //返回找到元素的地址,或表头地址 
}

有序合并链表

int Merg_L(LinkList La, LinkList Lb, LinkList &Lc)
{
    if(Lc)DestroyList_L(Lc);            //如果Lc不为空,销毁 
    if(InitList_L(Lc))return 1;         //初始化Lc 
    LinkList pa,pb,pc,t;                //定义指向三个链表元素的指针 
    LNode e;                            //定义一个结点变量,用于保存待插入学生数据 
    for(pa=La->next;pa!=La;pa=pa->next) 
    {
        e = *pa;                        //待插入数据赋给e 
        t = LocateElem_L(Lc,e,cmp)->prior; //查找e插入的位置,找到插入点前驱结点地址 
        ListInsert_L(t,e);              //插入e
    }
    for(pb=Lb->next;pb!=Lb;pb=pb->next)
    {
        e = *pb;
        t = LocateElem_L(Lc,e,cmp)->prior;
        ListInsert_L(t,e);
    }
}

声明

如果文章中有错误,欢迎指出,我会及时改正!

此文章为原创,如需转载,请注明转载地址!
http://blog.csdn.net/lliangw

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值