线性表链式存储(单循环链表)及其15种操作的实现


操作

时间复杂度(T(n))

空间复杂度(S(n))

判断是否为空

O(1)

O(1)

得到长度

O(n)

O(1)

转置链表

O(n)

O(1)

得到指定下标的元素

O(n)

O(1)

得到指定元素的下标

O(n)

O(1)

插入元素(只告诉插入到第几个结点之前,不告诉内存地址)

O(n)

搜索到指定下标的时间为O(n),更换指针指向的时间为O(1)

O(1)

需要开辟1个内存空间,即使插入1000个,也是O(1),因为需要的新内存空间是常数的,不是线性的

删除元素(只告诉删除第几个结点,不告诉地址)

O(n)

同上

O(1)

道理同插入元素

冒泡排序

O(n^2)

O(1)

道理同转置链表

将两个已经有序的链表(长度分别n,m)的合并到第一个链表,且保持新表有序

O(n+m)

虽然O(n+m)与O(n)同为线性阶,但是当m远大于n时,两者的差别会较大,写成O(n+m)更加准确

O(1)

不需要开辟新的内存空间,只需要改变指针的指向

/*   数据结构分析与学习专栏
*   Copyright (c) 2015, 山东大学 计算机科学与技术专业 学生
*   All rights reserved.
*   作    者:   高祥
*   完成日期:  2015 年 3 月 25 日
*   版 本 号:004

*任务描述:针对单循环链表,实现15个基本操作
*     1:头插法建立单循环链表 ;
*     2:尾插法建立单循环链表 ;
*     3:输出单循环链表的元素 ;
*     4:删除单循环链表指定位置的节点 ;
*     5:向单循环链表的指定位置插入节点;
*     6:查找单循环链表指定下标的元素 ;
*     7:求出给定元素在单循环链表中第一次出现的位置;
*     8: 将单循环链表的元素按照升序排序;
*     9:求单循环链表的长度;
*     10:判断当前单循环链表是否为空;
*     11:将单循环链表反转 ;
*     12:求两个单循环链表的并集到第三个单循环链表并按照升序排列(递归版本)  ;
*     13:求两个单循环链表的并集到第三个单循环链表并按照升序排列(非递归版本) ;
*     14:清空当前单循环链表 ;
*     15:销毁单循环链表  ;

*主要函数:
*   0:Status InitList(LinkList &L);//每次建立链表之前首先分配链表头结点的内存
*   1:Status InverseCreatList(LinkList L,int listsize);
//头插法输入listsize个元素,建立起有头结点的单循环链表L
*   2:Status OrderCreatList(LinkList L,int listsize);
//尾插法输入listsize个元素,建立起有头结点的单循环链表L
*   3:Status Output(LinkList L);//输出单循环链表
*   4:Status ListDelete(LinkList L,int index);//在带头结点的单循环链表L中,删除第index个元素
*   5:Status ListInsert(LinkList L,int index,ElemType elem);
//在带头结点的单循环链表L中第index个位置之前插入元素elem
*   6:Status GetElem(LinkList L,int index);
//L为带头结点的单循环链表的头指针,若第index个元素存在时,输出其值
*   7:Status GetIndex(LinkList L,ElemType elem);
//L为带头结点的单循环链表的头指针,若元素elem存在时,输出该元素在链表中的第一次//出现的位置
*   8:Status BubbleSort(LinkList L);//冒泡法排序
*   9:int ListLength(LinkList L);//求出单循环链表的长度
*   10:Status IsEmptyList(LinkList L);
//当且仅当头结点和第一个结点均不为空时,单循环链表才存在
*   11:Status ReverseList(LinkList L);//反转单循环链表
*   12:LinkList RecursiveMergeList(LinkList p,LinkList q);
//递归归并单循环链表并返回指向第一个结点的指针
*   13:void NonRecursiveMergeList(LinkList L1,LinkList L2);//非递归归并单循环链表
*   14:void ClearList(LinkList L);//清空链表L的所有节点(头结点外)
*   15:Status DestroyList(LinkList &L);// 销毁单循环链表L

*注意:只有Status InitList(LinkList &L)和Status DestroyList(LinkList &L)必须使用引用传参数(对main函数中指针本身的修改),其余的函数没有必要将形参声明为引用。
*/

#include<iostream>
#include <cstdlib>
#include<algorithm>
using namespace std;

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0

typedef int Status;//Status是函数的类型,其值是函数结果状态的代码
typedef int ElemType;//ElemType是数据元素的类型,使用时用户自行定义

typedef struct LNode
{
    ElemType data;
    struct LNode * next;
} LNode,*LinkList;

LinkList L1=NULL,L2=NULL;

Status InitList(LinkList &L);//每次建立链表之前首先分配链表头结点的内存

Status InverseCreatList(LinkList L,int listsize);//头插法输入listsize个元素,建立起有头结点的单循环链表L

Status OrderCreatList(LinkList L,int listsize);//尾插法输入listsize个元素,建立起有头结点的单循环链表L

Status Output(LinkList L);//输出单循环链表

Status ListDelete(LinkList L,int index);//在带头结点的单循环链表L中,删除第index个元素

Status ListInsert(LinkList L,int index,ElemType elem);//在带头结点的单循环链表L中第index个位置之前插入元素elem

Status GetElem(LinkList L,int index);//L为带头结点的单循环链表的头指针,若第index个元素存在时,输出其值

Status GetIndex(LinkList L,ElemType elem);//L为带头结点的单循环链表的头指针,若元素elem存在时,输出该元素在链表中的第一次出现的位置

Status BubbleSort(LinkList L);//冒泡法排序

int ListLength(LinkList L);//求出单循环链表的长度

Status IsEmptyList(LinkList L);//当且仅当头结点和第一个结点均不为空时,单循环链表才存在

Status ReverseList(LinkList L);//反转单循环链表

LinkList RecursiveMergeList(LinkList p,LinkList q);//递归归并单循环链表并返回指向第一个结点的指针

void NonRecursiveMergeList(LinkList L1,LinkList L2);//非递归归并单循环链表

void ClearList(LinkList L);//清空链表L的所有节点(头结点外)

Status DestroyList(LinkList &L);// 销毁单循环链表L

void Interaction();//输出操作

int main()
{
    Interaction();

    int operate;
    int listsize;

    while(cin>>operate)
    {
        switch (operate)
        {
        case 0:
            goto END;

        case 1:
            if(InitList(L1))
            {
                cout<<"请输入链表的大小:";
                int listsize;
                cin>>listsize;
                InverseCreatList(L1,listsize);
            }
            break;

        case 2:
            if(InitList(L1))
            {
                cout<<"请输入链表的大小:";
                cin>>listsize;
                InitList(L1);
                OrderCreatList(L1,listsize);
            }
            break;

        case 3:
            Output(L1);
            break;

        case 4:
            cout<<"请输入要删除元素的位置:";
            int index;
            cin>>index;
            ListDelete(L1,index);
            break;

        case 5:
            cout<<"请输入要插入的位置和元素的大小:";
            ElemType elem;
            cin>>index>>elem;
            ListInsert(L1,index,elem);
            break;

        case 6:
            cout<<"请输入要查找的元素的位置:";
            cin>>index;
            GetElem(L1,index);
            break;

        case 7:
            cout<<"请输入要查找的元素:";
            cin>>elem;
            GetIndex(L1,elem);
            break;

        case 8:
            BubbleSort(L1);
            break;

        case 9:
            cout<<"单循环链表的长度是:"<<ListLength(L1)<<endl;
            break;

        case 10:
            if(!IsEmptyList(L1))
            {
                cout<<"当前单循环链表不为空。\n";
            }
            else
            {
                cout<<"当前单循环链表为空。\n";
            }
            break;

        case 11:
            ReverseList(L1);
            break;

        case 12:
            InitList(L2);
            cout<<"请输入元素的个数(尾插法建立链表):";
            cin>>listsize;
            OrderCreatList(L2,listsize);

            BubbleSort(L1);
            BubbleSort(L2);

            L1->next=RecursiveMergeList(L1->next,L2->next);
            //该函数返回指向归并后链表的第一个节点,即头结点的后一个节点,将L1变为归并后的链表
            cout<<"归并后的链表是:";
            Output(L1);

            free(L2);//释放L2指针并置为空指针
            L2=NULL;
            break;

        case 13:
            InitList(L2);
            cout<<"请输入元素的个数(尾插法建立链表):";
            cin>>listsize;
            OrderCreatList(L2,listsize);

            BubbleSort(L1);
            BubbleSort(L2);

            NonRecursiveMergeList(L1,L2);
            cout<<"归并后的链表是:";
            Output(L1);

            free(L2);
            L2=NULL;
            break;

        case 14:
            ClearList(L1);
            break;

        case 15:
            DestroyList(L1);
            cout<<"释放内存完毕,销毁单循环链表成功。进行其他操作请先创建单循环链表。\n";
            break;

        default:
            cout<<"请输入正确的操作编号!\n";
            break;
        }
    }

END://释放两个指针的内存
    DestroyList(L1);
    DestroyList(L2);
    return 0;
}

Status InitList(LinkList &L)//每次建立链表之前首先分配链表头结点的内存
{
    L=(LinkList)malloc(sizeof(LNode));
    if(L)
    {
        cout<<"分配内存成功。已建立空单循环链表。\n";
        L->next=L;//头结点初始化:指向自身
        return OK;
    }
    cout<<"分配内存失败,已退出!\n";
    return FALSE;
}

Status InverseCreatList(LinkList L,int listsize)
//头插法输入listsize个元素,建立起有头结点的单循环链表L
//头插法特点:建立的链表元素顺序与输入的顺序相反,每次插入元素都插在头部,较好理解
{
    cout<<"请输入元素:";
    for(int i=1; i<=listsize; i++)
    {
        LinkList p=(LinkList)malloc(sizeof(LNode));
        cin>>p->data;
        p->next=L->next;
        L->next=p;
    }

    cout<<"新链表是:";
    Output(L);
    return OK;
}

Status OrderCreatList(LinkList L,int listsize)
//尾插法输入listsize个元素,建立起有头结点的单循环链表L
//尾插法特点:建立的链表元素顺序与输入的顺序相同,每次插入元素都插在尾部,细节注释如下
{
    LinkList r=L;//必须增加一个尾指针r,使其始终指向当前链表的尾结点
    cout<<"请输入元素:";
    for(int i=1; i<=listsize; i++)
    {
        LinkList p=(LinkList)malloc(sizeof(LNode));
        cin>>p->data;
        r->next=p;
        r=p;//更新尾指针
    }
    r->next=L;//终结链表,指向头结点

    cout<<"新链表是:";
    Output(L);
    return OK;
}

Status Output(LinkList L)//输出单循环链表
{
    if(!IsEmptyList(L))//增强程序的鲁棒性
    {
        LinkList p=L->next;
        while(p!=L)//终结循环的条件是当前结点≠头结点
        {
            cout<<p->data<<" ";
            p=p->next;
        }
        cout<<"\n";
    }
    else
    {
        cout<<"链表为空,无法输出。\n";
        return ERROR;
    }
}

Status ListDelete(LinkList L,int index)
//在带头结点的单循环链表L中,删除第index个元素
{
    if(index<1||index>ListLength(L))
    {
        cout<<"位置越界,操作失败,已退出。\n";
        return ERROR;
    }

    int j=0;//计数器
    LinkList p=L;//使之为头结点,而不是第一个节点,若p=L->next,会导致无法删除第一个节点
    while(j<=index-2)//当j==index-1,即p为删除位置的前一个结点时退出循环
    {
        if(p)
        {
            p=p->next;
            j++;
        }
        else
        {
            cout<<"位置越界,操作失败,已退出。\n";
            return ERROR;
        }
    }
    LinkList q=p->next;//被删除的结点
    cout<<"被删除的元素是:"<<q->data<<"\n";
    p->next=q->next;
    free(q);//释放对应节点的内存
    q=NULL;//置空指针,否则q会成为迷途指针,引发错误
    cout<<"新链表是:";
    Output(L);
    return OK;
}

Status ListInsert(LinkList L,int index,ElemType elem)
//在带头结点的单循环链表L中第index个位置之前插入元素elem
{
    if(index<1||index>ListLength(L))
    {
        cout<<"插入位置越界,操作失败,已退出。\n";
        return ERROR;
    }

    int j=0;
    LinkList p=L;//原理同删除元素
    while(j<=index-2)
    {
        if(p)
        {
            p=p->next;
            j++;
        }
        else
        {
            cout<<"插入位置越界,操作失败,已退出。\n";
            return FALSE;
        }
    }

    LinkList newnode=(LinkList)malloc(sizeof(LNode));
    newnode->data=elem;
    newnode->next=p->next;
    p->next=newnode;
    cout<<"插入元素成功。新链表是:";
    Output(L);
    return OK;
}

Status GetElem(LinkList L,int index)
//L为带头结点的单循环链表的头指针,若第index个元素存在时,输出其值
{
    if(index<1||index>ListLength(L))
    {
        cout<<"位置越界,操作错误,已退出。\n";
        return FALSE;
    }

    LinkList p=L;//初始化:p指向头结点
    int j=0; //计数器
    while(p&&j<index)//顺指针向后查找
    {
        p=p->next;
        j++;
    }
    cout<<"已找到,位置为"<<index<<"处的元素是:"<< p->data<<"。\n";
    return OK;
}

Status GetIndex(LinkList L,ElemType elem)
//L为带头结点的单循环链表的头指针,若元素elem存在时,输出该元素在链表中的第一次出现的位置
{
    if(!IsEmptyList(L))
    {
        int j=1;
        LinkList p=L->next;
        while(p!=L)
        {
            if(p->data==elem)
            {
                cout<<"元素"<<elem<<"是单循环链表中的第"<<j<<"个元素。\n";
                return OK;
            }
            j++;
            p=p->next;
        }
        cout<<"元素"<<elem<<"不在单循环链表中。\n";
        return FALSE;
    }
    else
    {
        cout<<"单循环链表为空,无法查找,已退出。\n";
        return FALSE;
    }
}

Status BubbleSort(LinkList L)//冒泡法排序
{
    if(!IsEmptyList(L))
    {
        LinkList p=L->next;
        while(p!=L)
        {
            LinkList q=p->next;
            while(q!=L)
            {
                if(q->data<p->data)
                {
                    swap(q->data,p->data);
                }
                q=q->next;
            }
            p=p->next;
            if(p!=L)
            {
                q=p->next;
            }
        }

        cout<<"排序后的链表是:";
        Output(L);
        return OK;
    }
    cout<<"链表为空,操作错误!已退出!\n";
}

int ListLength(LinkList L)//求出单循环链表的长度
{
    int cnt=0;
    LinkList p=L;
    if(p)
    {
        p=p->next;
    }
    while(p!=L)
    {
        cnt++;
        p=p->next;
    }
    return cnt;
}

Status IsEmptyList(LinkList L)//当且仅当头结点和第一个结点均不为空时,单循环链表才存在
{
    if(L!=NULL&&L->next!=L)//必须先检验L是否为NULL,若L==NULL,不事先检查的话,会Runtime Error
    {
        return FALSE;
    }
    return TRUE;
}

Status ReverseList(LinkList L)//反转单循环链表
{
    if(!IsEmptyList(L))
    {
        LinkList p1,p2,p3;//使用三个指针
        p1=L->next;//p1是当前头结点
        p2=L->next->next;
        p1->next=L;//头结点变为尾结点
        while(p2!=L)
        {
            p3=p2->next;//预存下一个节点的地址
            p2->next=p1;//指向前一个节点
            p1=p2;//更新指针
            p2=p3;
        }
        L->next=p1;//完成转置
        cout<<"转置后的链表为:";
        Output(L);
        return OK;
    }
    cout<<"链表为空,无法转置,已退出。\n";
    return FALSE;
}

LinkList RecursiveMergeList(LinkList p,LinkList q)//递归归并单循环链表并返回指向第一个结点的指针
{
    LinkList r;//新链表的结点
    while(p!=L1&&q!=L2)
    {
        if(p->data<=q->data)
        {
            r=p;
            r->next=RecursiveMergeList(p->next,q);//递归求出后续的节点
        }
        else
        {
            r=q;
            r->next=RecursiveMergeList(p,q->next);
        }
        return r;//返回指向新节点的指针
    }

    if(q==L2)//当第二条链表先归并完,那么直接返回L1的剩余第一个结点的指针即可(最终能够链接回到L1的头结点)
    {
        return p;
    }
    if(q!=L2)
/*
    当第二条链表没归并完,必须得一个个结点的递归,直至q==L2,返回指针p(此时p==L1),
    否则归并后的链表的最后一个结点并不指向L1的头结点(我们目的是将L1变为归并后的链表),
    这样输出L1的话,会形成死循环,无法判断终结的结点。
*/
    {
        r=q;
        r->next=RecursiveMergeList(p,q->next);
    }
}

void NonRecursiveMergeList(LinkList L1,LinkList L2)//非递归归并单循环链表
{
    LinkList p1,p2,p3;
    p1=L1->next;//第一条链表指针
    p2=L2->next;//第一条链表指针
    p3=L1;//归并后链表的头指针,使之为L1的头指针,即将L1变为归并后的链表
    while(p1!=L1&&p2!=L2)//当某一条链表归并完成后退出
    {
        if(p1->data<=p2->data)
        {
            p3->next=p1;
            p3=p1;
            p1=p1->next;
        }
        else
        {
            p3->next=p2;
            p3=p2;
            p2=p2->next;
        }
    }

    if(p2==L2)
    {
        p3->next=L1;
        return;
    }

    while(p2!=L2)
    {
        p3->next=p2;
        p3=p2;
        p2=p2->next;
    }
    p3->next=L1;//道理同递归归并的版本
}

void ClearList(LinkList L)//清空链表L的所有节点(头结点外)
{
    if(!IsEmptyList(L))
    {
        LinkList p=L->next;
        DestroyList(p);//销毁(释放)头结点后所有结点的内存
        L->next=L;//置空
        cout<<"清空单循环链表成功。\n";
    }
    else
    {
        cout<<"链表本身为空,无需清空!\n";
    }
}

Status DestroyList(LinkList &L)// 销毁单循环链表L
{
    if(!IsEmptyList(L))//必须先检验,防止L==NULL
    {
        LinkList p=L->next;
        free(L);//释放指针所指向的内存后,指针本身并不改变
        while(p!=L)
        {
            LinkList q=p->next;
            free(p);
            p=q;
        }
    }
    L=NULL;
    return OK;
}

void Interaction()//输出操作
{
    cout<<"请输入对应操作的序号:\n";
    cout<<"0:退出程序 ;\n";
    cout<<"1:头插法建立单循环链表 ;\n";
    cout<<"2:尾插法建立单循环链表 ;\n";
    cout<<"3:输出单循环链表的元素 ;\n";
    cout<<"4:删除单循环链表指定位置的节点 ;\n";
    cout<<"5:向单循环链表的指定位置插入节点;\n";
    cout<<"6:查找单链表指定下标的元素 ;\n";
    cout<<"7:求出给定元素在单链表中第一次出现的位置;\n";
    cout<<"8: 将单链表的元素按照升序排序;\n";
    cout<<"9:求单链表的长度;\n";
    cout<<"10:判断当前单链表是否为空;\n";
    cout<<"11:将单链表反转 ;\n";
    cout<<"12:求两个单链表的并集到第三个单链表并按照升序排列(递归版本)  ;\n";
    cout<<"13:求两个单链表的并集到第三个单链表并按照升序排列(非递归版本) ;\n";
    cout<<"14:清空当前单链表 ;\n";
    cout<<"15:销毁单链表  ;\n";
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值