线性表--顺序表和链表

目录

线性表的线性存储

顺序表

❀顺序表的存储结构描述

顺序表的基本运算

初始化

插入

删除

查找

链表

单链表的描述

❀单链表的定义

❀单链表的基本运算

建立单链表

求表长

查找

插入

删除

逆置

单链表中删除重复节点

求两个单链表集合的差集

❀循环链表

将HB连接到HA构成单循环链表。

❀双向链表

双链表中插入节点

双链表中删除节点


线性表

  • 线性表是n个数据元素的有限序列:(a1,a2,a3……an)。
  • 表中有且只有一个开始节点;有且仅有一个终端节点。除开始节点外,每个节点都有一个前驱节点;出最后一个节点外,每个节点都有一个后继节点。
  • 线性表具有以下三个特点:
    1.同一性。有同一种数据类型的元素组成,每一个元素都是相同的数据类型。
    2.有穷性。线性表由有限个数据元素组成,表程度就是表中数据元素的个数。
    3.有序性。线性表相邻元素之间存在线性关系。
  • 线性表的运算
    1.InitList(L)。线性表的初始化,构建一个空的线性表。
    2.ListLength(L)。求线性表的长度,返回线性表中数据元素的个数。
    3.GetElem(L,i,x)。用x返回线性表中第i个数据元素的值。
    4.LocationElem(L,x)。按值查找,确定元素x在L中的位置。
    5.ListInsert(L,i,x)。插入操作,在L中第i个位置之前插入x,L的长度加1.
    6.ListDelete(L,i)。删除操作。删除L中第i个元素,L的长度减1。
    7.ListEmpty(L)。判断L是否为空列表。空返回TRUE,非空返回FALSE。
    8.ClearList(L)。将已知的线性表L置为空表。
    9.DestoryList(L)。销毁线性表L。

线性表的线性存储

1.顺序表

顺序表的存储结构描述


#define MAXSIZE    <线性表的最大长度>
tepedef struct
{
    EleType else[MAXSIZE];
    int length;    //线性表长度
}Seqlist;
//为了使线性表中数据元素的位序保持一致,不使用下标为0的单元

顺序表的基本运算


1.初始化

void Init_SeqList(SeqList* L)
{       
    L->length = 0;
}

2.插入

操作步骤:
  ①将an~ai按照从后向前依次向下移动,将新元素插入空出的第i个位置
  ②修改表长

int Insert_SeqList(SeqList *L,int i,ElemType x) 
{
    int j;
    if(L->length == MAXSIZE-1)//检验表空间是否已满 
    {
        printf("表满");
        return OVERFLOW;
    }
    if(i<1 || i>L->length+1)//检验插入位置是否正确 
    {
        printf("位置错");
        return ERROR;
    }
    for( j=L->length;j>=i;j++)
    {
        L->elem[i+1] = L->elem[i];
    }
    L->elem[i] = x;
    L->length++;//修改表长
    return TRUE;//插入成功,返回结果
}

3.删除

操作步骤:

①将a(i+1)~an依次向上移动

②将线性表的长度减1

int Delete_SeqList(SeqList* L,int i,ElemType* e) 
{    
    int j;
    if(i<1 || i>L->length)//检验空表删除位置的合法性
    {
        printf("不存在第i个元素");
        reutrn ERROR;
    }
    *e = L->elem[i];//将删除的第i个元素存储
    for(j=i;j<L->length;j++) 
    {
        L->elem[i] = L->elem[i+1];
    }
    L->length--;//线性表的长度减1
    return TRUE;//删除成功
}

4.查找

操作步骤

①从线性表的第一个元素a1依次向后查找元素和x作比较,直至找到后返回位置,如果查找到L->length、还没有找到x,则返回FALSE。

int Location_SeqList(Seqlist* L,ElemType x)
{        
    int i=1;
    while(i<=L->length && i->elem[i]!= x)
    {
        i++;
    }
    if(i>L->length)
    {
        return FALSE;//查找失败
    }
    return i;//返回元素x的位置
}

2.链表


单链表的描述


1.链表是通过一组任意位置的存储单元来存储线性表中的数据元素,对于每个元素ai,除了存储本身的信息外,还必须包含直接后继元素信息的位置。
2.链表中的每个节点都包含两个域:数据域、指针域。
3.头结点、头指针:为了操作方便,在单链表的第一个节点之前添加一个附加节点,称为“头结点”。头结点的数据域可以存储标题、标称信息等,也可以不存储任何信息,其指针域存储链表的第一个节点的首地址,头结点由指针变量指向。由于最后一个节点没有后继节点,因此最后一个节点的指针域为空(NULL)。


单链表的定义

typedef struct node
{
    DateType date;//数据域
    struct node* next;//指针域
}Lnode;*LinkList;


单链表的基本运算


1.建立单链表
①头插法建立单链表

头插法建立单链表是指在链表的头部插入节点建立单链表,实现方法如下:

①申请一个头节点,并将头节点的指针域置为空。

②依次读入数据元素,如果不是结束标志-1,则继续申请节点。

③将新节点插入链表的头节点之后,将接下来的节点插入到最后一个节点之前。数据读入顺序与逻辑表中的元素顺序正好相反。

LinkList Creat_LinkList1()
{
    LinkList H = (LinkList)malloc(sizeof(LNode));    //创建头节点
    H->next = NULL;
    LNode *s;
    int x;
    scanf("%d",&x);
    while(x!=-1)
    {
        s = (LinlList)malloc(sizeof(LNode));
        s->date = x;
        s->next = H->next;
        H->next = s;
        scanf(%d",&x);
    }
    return H;
}

②尾插法建立单链表

①尾插法建立单链表是指在单链表的尾部插入节点,所以新增一个指针来指向链表中的尾节点,方便新节点插入链表的尾部。

②数据读入顺序和逻辑表中的顺序一致。

//尾插法建立单链表
LinkList Creat_LinkList2()
{
    LinkList H = (LinkList)malloc(sizeof(LNode));//创建头节点
    H->next = NULL;
    LNode *s,*r = H;
    int x;
    scanf("%d",&x);
    while(x!=-1)
    {
        s = (LinkList)malloc(sizeof(LNode));
        s->date = x;
        r->next = s;
        r = s;
        scanf("%d",&x);
    }
    r->next = NULL;//尾节点
    return H;
}

  2.求表长

操作步骤:

①设置一个指针p和计数器count,初始化p指向头节点H,count为0.

②若p节点还有后继节点,则p向后移动,计数器+1.(线性表的长度不包含头节点)。

③直到p-next == NULL为止,返回计数器,即为链表的长度

int Length_LinkList(LinkList)
{
    LNode* p = H;//使指针p指向头节点,统计的链表长度不包含头节点
    int count = 0;
    while(p->next!=NULL)
    {
        p = p->next;
        count++;
    }
    return count;
}

 3.查找

①按序号查找

Get_LinkList(H,k)

操作步骤:从链表的第一个节电起判断当前节点是否为第k个,若是返回,否则继续查找,直到结束返回空。

LinkList Get_LinkList(L,k)
{
    LNode* p = H;
    int count = 0;
    while(p->next!=NULL && count<k)
    {
        count++;
        p = p->next;
    }
    if(count == k)
    {
        return p;
    }
    return NULL;//链表中没有第k个节点
}

②按值查找

操作步骤:从第一个元素节点起,判断当前值是否为x,若是返回该节点的指针,否二继续向后查找,直到表结束返回空。

LNode* Locate(LinkList H,DateType x)
{
    LinkList p = H;
    while(p->next != NULL && p->date != x)
    {
        p = p->next;
    }
    return p;
}

4.插入

①说明:p为待插入节点前面的节点,s指向待插入的节点,将s指向的节点插入到p指向节点的后边。

操作步骤:

s->next = p->next;
p->next = s;

②说明:p为待插入节点后面的节点,s指向待插入的节点,将s指向的节点插入到p指向节点的前面。

操作步骤:找到p指向节点的前驱指针q,将s指向的节点插入到q指向的节点的后边。

q = H;
while(q->next != p)
{
    q = q->next;
}
s->next = q->next;
q->next = s;

总结:将新节点s插入到第i个节点的位置上,实现步骤如下

  • 查找第i-1个节点,若存在继续,否则返回空。
  • 创建新节点
  • 新节点的指针域指向第原本位置上的第i个节点。
  • 第i-1个节点的指针域指向新节点
int Insert_LinkList(LinkList H,int i,DateType x)
{
    Lnode *p,*s;
    p = Get_LinkList(H,i-1);//查找第i-1个节点
    if(!p)//如果没有找到底i-1个节点
    {        
        return NULL;
    }
    else
    {
        s = (LinkList)malloc(sizeof(LNode));//申请新节点
        s->date = x;
        s->next = p->next;//新节点插入第i-1个节点后
        p->next = s;
        return TRUE;//插入成功
    }
}

5.删除

删除链表中的第i个节点,操作步骤:

①找到第i-1和第i个节点,若存在继续,否则返回空。

②-1节点的指针域指向i+1节点。

③释放第i个节点的空间。

int Del_LinkList(LinkList H,int i)
{
    LinkList p,q;
    p = Get_ListList(H,i-1);
    if(p==NULL)
    {
        printf("第i-1个节点不存在");
        return ERROR;
    }
    else if(p->next = NULL)
    {
        printf("第i个节点不存在");
        returnERROR;
    }
    else 
    {
        q = p->next;//q是待插入节点
        p->next = q
    }
}

6.逆置

依次取原链表中的每个节点,将其作为第一个节点插入新链表中,指针p指向当前节点,p为空时结束。

void Reverse(LinkList H)
{
    Lnode *p,*q;
    p = H->next;
    H->next = NULL;//将尾节点置为空
    while(p)
    {
        q = p;
        p = p->next;
        q->next = H->next;//头插法建立单链表
        H->next = q;
    }
}

7.单链表中删除重复节点

实现步骤:用指针p指向第一个节点,从它的直接后继开始找与其值相同的节点删除,p指向下一个节点,p指向最后一个节点时结束。

void pur_LinkList(LinkList H)
{
    Lnode *p,*q,*r;
    p =H->next;
    if(!p)
    {
        while(p->next)
        {
            q = p;
            while(q->next)
            {
                if(q->next->date == p->date)
                {
                    r = q->next;//使指针r指向待删除的节点
                    q->next = r->next;
                    free(r);
                }
                else
                {
                    q = q->next;
                }
            }
            p = p->next;//将指针p向后移动,继续从其直接后继节点查找重复节点删除
        }
    }
}

8.求两个单链表集合的差集

实现步骤:假设单链表A用LA表示,单链表B用LB表示,求A-B的差值:对于LA链表中的每个元素,在链表LB中查找,若存在与额相同的元素,则从LA中将其删除。

void Difference(LinikList LA,LinkList LB)
{
    Lnode *p,*q,*r,*pre;
    pre = LA;
    p = LA->next;//p指向表中的某一节点,pre始终指向p的前驱
    while(!p)
    {
        q = LB->next;
        while(q != NULL && q->date != p->date)
        {
            q = q->next;
        }
        if(q!=NULL)
        {
            r = p;
            pre->next = r->next;    
            p = p->next;
            free(r);
        }
        else
        {
            pre = p;
            p = p->next;
        }
    }
}

循环链表

在单链表的的基础上,将其最后一个节点的指针域指向该链表头节点,使链表头尾相连构成单循环链表。实际中多采用尾指针rear表示单循环链表。

1.将HB连接到HA构成单循环链表。

实现步骤:

①查找HA的尾节点,将HA尾结点的指针域置为HB的开始节点。

②释放HB的头结点,将HB的尾结点的指针域置为HA的头结点。

p = rearA -> next;    //保存HA的头结点
rearA -> next = rearB->next->next;    //将HA尾结点的指针域改为HB的开始节点
free(rearB -> next);    //释放HB链表的头结
rearB -> next = p;    //将HB的尾结点的指针域指向HA的头结点

双向链表

一个节点拥有两个指针,分别指向该节点的前驱结点和后继节点,头节点的前驱结点为尾结点,尾结点的后继节点为头结点。

定义方法:

typedef struct dlnode
{
    DateType date;
    struct dlnode *prior,*next;
};

1.双链表中插入节点

设p指向某节点,s指向待插入到p节点前的新节点。

实现步骤

①将s节点的piror指针修改为p的piror指针值。

②将p前驱指针的next指针修改为s指针指向的节点。

③将p的piror指针修改为s指针值。

④将s的next指针修改为p指针值。

图示

/*
p指向某节点
s指向待插入到p节点前面的节点
*/

s->prior= p->piror;
p->prior->next = s;
s->next = p;
p->prior = s;

 2.双链表中删除节点

设p指向待删除的节点。

实现步骤

①将p指针前驱结点的next指针置为p指针指向节点的next指针值。

②将p指针后继节点的prior指针置为p指针指向节点的prior指针值。

③释放p指针指向节点的空间。

图示

p->prior->next = p->next;
p->next->prior = p->prior;
free(p);

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小s的s

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值