数据结构与算法——线性表的链式存储

线性表的链式存储

1.线性表的链式存储结构

顺序:用一组地址连续的存储单元依次存储线性表中每个数据元素。

链式:用一组地址任意的存储单元(地址可以连续也可以不连续),依次存储线性表中的各数据元素。

链式存储结构中的每个存储单元称为“结点”,节点包含一个数据域和一个指针域

数据域存放数据元素信息;

指针域存放后继结点地址;

数据元素之间的逻辑关系通过结点中的指针表示;

通常由第一个结点开始,逐一访问所有结点。

具有n个数据元素的线性表对应的n个结点通过链接方式链接成一个链表,即为线性表的链式存储结构

1.1单链表

链表中每个链结点中仅包含一个指针域,这样的链表称为单链表。

单链表的结点结构

单链表结构

head:头指针,保存链表第一个结点的地址

a1处结点:头结点(在链表的第一个结点之前附设一个结点),数据域为空,指针域指向第一个结点。

注意:带头结点的单链表其头结点的引入使得单链表的头指针永远不为空,从而给插入、删除等操作带来了方便。

an处结点:尾结点,指针域的值为空(NULL)

1.1.1结点的数据类型
typedef int ElemType;    //ElemType数据元素的数据类型
typedef struct LNode     //LNode为结点类型名
{
    ElemType data;       //data代表数据元素
    struct LNode *next;  //next为指向下一个结点的指针
}LinkNode;               //单链表结点类型

2.单链表的基本操作

2.1单链表的基本操作概念

//p、q为指向任意结点的指针

空表:head->next==NULL

表尾:p->next==NULL

指针后移:p=p->next

结点连接:p->next=q(q结点放在p结点之后)

前驱:若p->next==q,则p指向q的前驱结点

2.2初始化单链表

void InitList(LinkNode *&L)//&引用LinkNode类型的L指针,内部改外部
{//L为指向单链表的头指针
    L=new LinkNode;//分配空间,作为为头结点
    L->next=NULL;
}

在函数中,需要改变单链表的头指针,因此参数L设计为一个指针的引用,即引用的类型为指针。

2.3判断表空

bool ListEmpty(LinkNode *L)
{//L为指向单链表的头指针
    if(L->next==NULL)  //头结点指针域为空
        return ture;
    else
        return false;
}

2.4求单链表中当前元素的个数

int ListLength(LinkNode *L)
{//L为指向单链表的头指针
    int n=0;
    LinkNode *p=L->next;
    while (p){
       n++;         //计数器+1
       p=p->next;   //指针后移
    }
    return n;
}
//时间复杂度:O(n)

2.5遍历单链表

void TraverseList(LinkNode *L)
{//L为指向单链表的头指针
    LinkNode *p=L->next;
    while(p)
    {
        count<<p->data<<" ";
        p=p->next;
    }
    cout<<endl;
}

3.单链表的重要基本操作

3.1单链表的查找操作

查找指定结点:

设置一个跟踪链表结点的指针p,初始时p指向链表中的第一个结点,然后顺着next域依次指向每个结点。每指向一个结点就判断其是否等于指定结点,

若是,则返回该结点地址。

否则继续向后搜索,直到p为NULL,表示链表中无此元素,返回NULL。

int Find_item(LinkNode *L,ElemType item)
{//L为指向单链表的头指针
    LinkNode *p=L->next;
    int pos=1;//结点位序
    while(p && p->data !=item)
    {//从单链表第一个结点开始顺序查找所有结点
        p=p->next;
        pos++;
    }
    if (p) 
        return pos;//返回位置编号
    else
        return 0;  //查找失败
}

3.2获取单链表中指定位置上的数据元素 

bool Find_pos(LinkNode *L,int pos,ElemType &item)
{//L为指向单链表的头指针
    LinkNode *p=L->next;
    int i=1;//结点位序
    while (p&&i !=pos)
    {
        p=p->next;
        i++;
    }
    if(p==NULL)
    {//查找不成功,退出运行
        cout<<"位置无效"<<endl;
        return false;
    }
    item=p->data;
    return true;
}

3.3单链表的插入操作

3.3.1向线性表指定位置插入一个新元素

单链表结点的插入利用修改结点指针域的值,使其指向新的链接位置来完成插入操作,无需移动任何元素。

假定在链表中指定结点之前插入一个新结点,要完成这种插入必须首先找到所插位置的前一个结点,再进行插入。假设指针p指向待插位置的前驱结点,指针t指向新结点。

bool ListInsert(LinkNode *L,int pos,ElemType item)//向线性表指定位置插入一个新元素
{ 
    LinkNode *p=L;
    int i=0;
    while(p&&i !=pos-1)
    {//查找pos的前驱
        p=p->next;
        i++;
    }
    if(p==NULL)
    {//查找不成功,退出运行
        cout<<"插入位置无效"<<endl;
        return falsel
    }
    LinkNode *t=new LinkNode;//下方图片1处
    t->data=item;            //下方图片1处
    t->next=p->next;         //下方图片2处
    p->next=t;               //下方图片3处
    return ture;
} 
//时间复杂度:O(n)

 

3.3.2链表表头插入法

在单链表的头结点之后第一个数据结点之前插入一个新结点,head指向表头结点,head->next表示表头的后继结点,指针t指向待插入结点。

LinkNode *t=new LinkNode;//下图1处
t->data=d;               //下图1处
t->next=head->next;      //下图2处
head->next=t;            //下图3处

3.3.3链表表尾插入法
LinkNode *t=new LinkNode;//下图1处
t->data=d;               //下图1处
t->next=NULL;            //下图1处
last->next=t;            //下图2处
last=t                   //下图3处

 

3.4单链表的删除操作

3.4.1删除指定位置的结点

首先找到被删除位置的前一个结点,并用指针p指向删除位置的前驱结点,指针t指向被删除的结点;将指针p所指结点的指针域修改为t所指结点的后继;释放被删结点t,即delete t.

bool ListDelete(LinkNode *L,int pos,ElemType &item)
{
    LinkNode *p=L,*t;
    int i=0;
    while(p->next&&i !=pos-1)
    {//查找pos的前驱
        p=p->next;
        i++;
    }
    if(p->next==NULL)
    {//查找不成功,退出运行
        cout<<"删除位置无效"<<endl;
        return false;
    }
    t=p->next;         //1处t为被删除结点
    p->next=t->next;   //2处删除t的链接关系
    item=t->data;      //保存被删除结点的值
    delete t;          //3处释放被删除结点
    return ture;
}
//时间复杂度:O(n)
 3.4.2撤销单链表
void DestroyList(LinkNode *&L)
{//L为指向单链表的头指针
    LinkNode *p;
    while (L)
    {
        p=L;
        L=L->next;//使用L指针保存下一结点的位置
        delete p;
    }
}

4.链式存储结构的特点

4.1优点

1、不需要占用连续存储空间,使用链表前不用事先估计存储空间大小。

2、插入和删除操作时,不需要移动大量元素

4.2缺点

1、操作算法复杂。

2、不能随机存取

3、需要额外空间来表示元素间的关系,空间代价较高

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值