线性表之单循环链表

程序员没有午休,话说好多年不睡午觉了哈,利用中午时间调试好了单循环链表的程序。据说某学长当年面试的时候被问到“如何用循环链表输出1-10”?看来这个问题还是很火的哈~~~本文中介绍的单循环链表不具有一般意义,它有以下的特征:带头结点,只设头指针(有些循环链表还设有尾指针)。我们知道,循环链表中没有NULL指针,涉及遍历操作时,其终止条件就不再是像非循环链表那样判别p或p->next是否为空,而是判别它们是否等于某一指定指针,如头指针或尾指针等,当然在本文中,是头指针。代码部分与我的上一篇博客《线性表之单链表》大体相同,但是也有不同之处,具体为增加了连接函数,以及在遍历,判空的时候与单链表还是有一些不同的,具体请读者自己体会。话不多说,上代码,错误之处,还请指出!

#include<cstdio>
#include<cstdlib>

typedef char Datatype;
typedef struct node{
    Datatype data;
    struct node *next;
}ListNode;
typedef ListNode *LinkList;

//****************************建立单循环链表*************************************
LinkList CreateListR1(){//尾插法建立带头结点的单循环链表,返回单循环链表的头指针
    char ch;
    LinkList head=(ListNode *)malloc(sizeof(ListNode));  //生成头结点
    ListNode *s,*r;       //工作指针和尾指针
    r=head;               //尾指针初值也指向头结点
    while((ch=getchar())!='\n'){
        s=(ListNode *)malloc(sizeof(ListNode));     //生成新结点
        s->data=ch;       //将读入的数据放入新结点的数据域中
        r->next=s;        //连接原链表与新结点
        r=s;              //尾指针移位
    }
    r->next=head;         //终端结点的指针域指向头结点,或空表的头结点指针域指向自身
    return head;
}

//******************************单循环链表的查找运算******************************

ListNode* GetNode(LinkList head,int i){
    //在带头结点的单循环链表head中查找第i个结点(设头结点为第0个结点)
    //若找到,则返回该结点的存储位置,否则返回NULL
    int j=0;
    ListNode *p=head;      //从头结点开始扫描
    while(p->next!=head&&j<i){   //顺指针向后扫描,直到p->next为头指针或j=i为止
        p=p->next;
        j++;
    }
    if(j==i)  return p;    //找到了第i个结点
    else return NULL;      //当i<0或0<i<j时,找不到第i个结点
}

ListNode* LocateNode(LinkList head,Datatype key){
    //在带头结点的单循环链表head中查找其值为key的结点
    //若找到,则返回首次找到的其值为key的结点的存储位置,否则返回头结点地址
    ListNode *p=head->next;    //从开始结点比较。表非空,p初始值指向开始结点
    while(p!=head && p->data!=key){    //直到p为head或p->data为key为止
        p=p->next;             //扫描下一结点
    }
    return p;                  //若p=head,则查找失败,否则p指向值为key的结点
}

//**************************单循环链表的插入与删除运算*****************************

void InsertList(LinkList head,Datatype x,int i){
    //将值为x的新结点插入到带头结点的单循环链表head的第i个结点的位置上
    ListNode *p;
    p=GetNode(head,i-1);     //寻找第i-1个结点
    if(p==NULL)              //i<1或i>n+1时插入位置i有错
        printf("Position Error!");
    ListNode *s=(ListNode *)malloc(sizeof(ListNode));
    s->data=x;
    s->next=p->next;
    p->next=s;
}

void DeleteList(LinkList head,int i){
    //删除带头结点的单循环链表head上的第i个结点
    //注意:设单循环链表的长度为n,则删去第i个结点仅当1≤i≤n时是合法的
    ListNode *p,*r;
    p=GetNode(head,i-1);            //找到第i-1个结点
    if(p==NULL)                     //i<1或i>n时,删除位置错
        printf("Position Error!");
    r=p->next;                      //使r指向被删除的第i个结点
    p->next=r->next;                 //将第i个结点从链上摘下
    free(r);                        //释放结点ai的空间给存储池
}

//*******************************单循环链表的其他函数*********************************
void PrintList(LinkList head){
    //带头结点的单循环链表head的输出函数
    ListNode *p=head->next;
    while(p!=head){
        printf("%c",p->data);
        p=p->next;
        printf("->");
    }
    printf("\n");
}

int ListLength(LinkList head){
    //计算带头结点的单循环链表head的长度
    ListNode *p=head->next;
    int i=0;
    while(p!=head){
        i++;
        p=p->next;
    }
    return i;
}

bool ListEmpty(LinkList head){
    //判断带头结点的单循环链表head是否是空链表
    //若是空链表则返回true,否则返回false
    if(head->next==head)
        return true;
    else return false;
}

void DestroyList(LinkList head){
    //销毁单循环链表head
    ListNode *p;
    while(head){
        p=head->next;
        free(head);
        head=p;
    }
}

LinkList Connect(LinkList A,LinkList B){
    //实现将两个单循环链表表A(a1,a2,…,an)和B(b1,b2,…,bm)
    //连接成一个单循环链表表C(a1,…,an,b1,…bm)的运算
    ListNode *p=A;             //工作指针赋初值为A的头指针
    while(p->next!=A){         //遍历A链表,找到结点an,从而找到A链表的尾指针
        p=p->next;
    }
    p->next=B->next;           //将B链表的开始结点链到A表尾
    p=B;
    while(p->next!=B){         //工作指针赋初值为B的头指针
        p=p->next;             //遍历B链表,找到结点bn,从而找到B链表的尾指针
    }
    p->next=A;                 //将B链表的尾结点链到A表的头结点
    free(B);                   //释放B链表的头结点
    return A;                  //返回新循环链表的头指针
}


//*********************************测试函数****************************************

int main(){
    printf("用尾插法生成单循环链表1:\n");
    LinkList head=CreateListR1();
    PrintList(head);
    if(ListEmpty(head))
        printf("链表1是空链表\n");
    else
        printf("链表1不是空链表,长度为%d\n",ListLength(head));
    printf("链表1第3个位置上的元素是:%c\n",*GetNode(head,3));
    printf("链表1在第4个位置上插入元素‘z’后为:\n");
    InsertList(head,'z',4);
    PrintList(head);
    printf("链表1删除第5个位置上元素后为:\n");
    DeleteList(head,5);
    PrintList(head);
    printf("用尾插法生成单循环链表2:\n");
    LinkList head2=CreateListR1();
    PrintList(head2);
    printf("连接链表1与链表2,得到的新链表为:\n");
    LinkList C=Connect(head,head2);
    PrintList(C);
    DestroyList(head);
    DestroyList(head2);
    DestroyList(C);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值