单链表中基本操作

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/fighting123678/article/details/82700579

头指针—(头结点)(可以没有)—首元结点

//库函数头文件包含
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>

//函数状态码定义
#define TRUE        1
#define FALSE       0
#define OK          1
#define ERROR       0
#define INFEASIBLE -1
#define OVERFLOW   -2

typedef int  Status;
typedef int  ElemType; //假设线性表中的元素均为整型

typedef struct LNode
{
    ElemType data;//data是ElemType类型的;
    struct LNode *next;//next是*类型;
}LNode,*LinkList;//*在LinkList前面

因为链表中,以元素(数据元素的映象) + 指针(指示后继元素存储位置) = 结点(表示数据元素 或 数据元素的映象),以“结点的序列”表示线性表称作链表。


一、链表初始化

Status InitList(LinkList &L)
{
    L=(LinkList)malloc(sizeof(LNode));//生成新结点作为头指针,用头指针L指向头结点;
    if(L==NULL) return ERROR;
    L->next=NULL;//头结点的指针域为空
    return OK;
}

二、链表的创建

方式1:前插法创建单链表
此方法采用的是倒叙插入的方式,比如输入的是1 2 3,但是实际上插入的数据排序为3 2 1;

void CreateList_H(LinkList &L,int n)//逆位序输入n个元素的值
{
    LinkList p;//p是LinkList类型的;
    L=(LinkList)malloc(sizeof(LNode));//新建一个带头结点的单链表L;
    if(L==NULL) return ERROR;
    L->next=NULL;//将单链表设置为空
    for(int i=0;i<n;i++)
    {
        p=(LinkList)malloc(sizeof(LNode));//生成新结点;
        scanf("%d",&p->data);//不要忘记输入元素;//这里千万不要忘记加&符号
        p->next=L->next;//p->next等于的是L->next,而不是NULL
        L->next=p;//插入到表头
    }
}

这里写图片描述
首先创建一个带有头结点的空的单链表,然后倒叙(代码i是从n开始不断减一)不断创建新结点,输入值(千万别忘了),建立链表关系。

方式2:后插法创建单链表
此方法采用的是正叙插入的方式,比如输入的是1 2 3,实际上插入的数据排序为1 2 3;
倒叙插入数据的时候就是一直在头结点之后进行插入数据,因此不需要考虑太多的问题,但是,正序插入数据的时候,是不断在新插入的数据之后再插入数据,因此必须要用另外一个变量不断指向新插入的结点,以便于插入后续的结点。

void CreateList_H(LinkList &L,int n)
{
    LinkList p,r;
    L=(LinkList)malloc(sizeof(LNode));//新建一个带头结点的单链表L;
    if(L==NULL) return ERROR;
    L->next=NULL;//将单链表设置为空
    r=L;//注意是在这里给r赋值的,让r指向头结点//这里是为了让r不断指向新创立的结点;
    for(int i=0;i<n;i++)
    {
        p=(LinkList)malloc(sizeof(LNode));
        scanf("%d",&p->data);
        p->next=NULL;//因为新的结点的位置一直都是在尾结点之前,所以新结点的下一个一定是NULL;
        r->next=p;//将p插入到r之后;
        r=p;//让r指向新的结点p;
    }
}

注意:
(1)上面的操作都是对于单链表的操作
(2)注意r赋值的位置

算法的时间复杂度为:O(Listlength(L))


三、链表的插入

在链表中插入结点只需要修改指针。但同时,若要在第 i 个结点之前插入元素,修改的是第 i-1 个结点的指针。因此,在单链表中第 i 个结点之前进行插入的基本操作为: 找到线性表中第i-1个结点,然后修改其指向后继的指针。

Status ListInsert_L(LinkList&L,int i,ElemType e)//在线性表第i个位置插入元素e//插入和创建不一样,插入是在创建的基础上进行的改动;
{
    LinkList p,s;
    p=L;//因为现在需要找的位置是插入位置的前一个,插入的位置也有可能为头结点的后面,因此以p为起点;
    int j=0;//因为以p为起点,所以j的初始值为0;
    while(p&&j<i-1)//这里是在寻找要插入结点位置的前一个
    {
        p=p->next;
        j++;
    }
    if(!p||j>i-1) return ERROR;//p为空的话就停止;
    s=(LinkList)malloc(sizeof(LNode));//要为插入的地方创建新的结点;
    s->data=e;//千万不要忘记在创建结点之后给新结点赋值;
    s->next=p->next;
    p->next=s;
    return OK;
}

注意:
(1)千万不要忘记在创建新结点之后赋值
(2)插入的时候,先要找到前一个插入的位置,因为插入的位置也有可能为头结点的后面,因此以p为起点,所以j的初始值为0(这里还用了一个变量j是因为怕有错误的位置出现)。找到位置之后,创建新的结点,输入元素,然后再将新结点放到找到的p的位置的后面;
(3)在p后面插入s的操作

s = (LinkList) malloc ( sizeof (LNode)); // 生成新结点
s->data = e; 
s->next = p->next;      p->next = s; // 插入

算法的时间复杂度为:O(ListLength(L))


四、链表的删除

Status ListDelete_L(LinkList&L,int i,ElemType& e)//注意e前有&号
{
    LinkList p,r;
    p=L;//有可能删除的是第一个元素,所以p最开始的位置是头结点;
    int j=0;
    while(p->next&&j<i-1)//因为要删除的是下一个元素,所以要保证下一个元素有数,所以在while中是p->next//保证p不是最后一个元素
    {
        p=p->next;
        j++;
    }
    if(!(p->next)||j>i-1) return ERROR;
    r=p->next;//先记录要删除的位置,否则删除不了;//不需要重新分配,因为p就已经有结点空间了;
    e=p->next->data;
    p->next=p->next->next;
    free(r);
    return OK;
}

注意:
(1)p最开始指向的位置是头结点,因为万一删除的位置是首元结点
(2)while(p->next&&j<i-1)与插入不同,这样是为了保证p指向的不是最后一个元素,因为删除的时候如果想要删除的是最后一个元素的话,要找到最后一个元素的前一个;插入的话,可以一直找到最后一个元素,因为可以在最后一个元素后插入元素。删除则不同,不可删除最后一个元素之后的元素。
(3)注意记录要删除元素的位置
(4)在单链表中删除第 i 个结点的基本操作为:找到线性表中第i-1个结点,修改其指向后继的指针。

q = p->next;   p->next = q->next;  
e = q->data;     free(q);

算法的时间复杂度为:O(ListLength(L))

删除和插入一样,都需要找到要插入或者删除位置的前一个,但是还是有不同点,删除的时候要保证要删除的位置有数,不能是空的,所以在while中的判断不同

五、链表的清空

void ClearList(&L)// 将单链表重新置为一个空表
{
    LinkList r;
    //p=L;没有必要,因为要置为空表,所以不断删除头结点之后的元素即可,不需要借助另外一个来删除;
    while(L->next)
    {
        r=L->next;
        L->next=r->next;
        free(r);
    }
}

注意:
(1)在置为空表的时候,不需要借助别的元素,因为直接删除头结点之后的东西

算法时间复杂度:O(ListLength(L))


六、查询某位置的元素

求在第i个位置的元素值

Status GetElen_L(LinkList L,int i,ElemType &e)
{
    LinkList p;
    p=L->next;//查找元素从第一个元素开始查找就可以啦
    int j=1;
    while(p&&j<i)
    {
        p=p->next;
        j++;
    }
    if(!p&&j>i) return ERROR;
    e=p->data;
    return OK;
}

注意:
(1)查找元素的时候,从第一个元素开始查找就可以了

算法时间复杂度:O(ListLength(L))

查询元素是一定从第一个开始查询,知道找到第i个位置为止

因为之前L=(LinkList)malloc(sizeof(LNode));所以当p=L的时候,其实p就已经有了一块结点,如果之前没有对L进行动态分配空间的话,p要单独分配一个空间。

猜你喜欢

转载自blog.csdn.net/fighting123678/article/details/82700579
今日推荐