1.线性表【线性结构】

本文详细介绍了线性表的顺序表示和链式表示,包括顺序表的定义、查找、插入和删除操作,以及链表的单链表、双向链表和循环链表的特性。在顺序表中,查找、插入和删除的时间复杂度平均为O(n),而在链表中,这些操作各有特点,如单链表插入需考虑前后节点关系。

1.顺序表示

1.1 定义

数组从0开始,顺序表从1开始

#define MaxSize 100     //最大长度
typedef struct{
    ElemType *date;     //指向数据元素的基地址
    int length;         //线性表的当前长度
}SqList;

bool InitList_Sq(SqList &L)
{
    L.data = new ElemType[MaxSize];
    if(!L.data)
        exit(OVERFLOW);
    L.length = 0;
    return true;
}

 

1.2 基本操作

1.2.1 查找

注意:是返回其位序

//在线性表L中查找值为e的数据元素,并返回其位序
int LocateElem_Sq(SqList L, ElemType e)
{
    for(int i = 0; i < L.length; i++)
    {
        if(L.date[i] == e)
            return i+1;
    }
    return 0;
}

 
算法平均时间复杂度为O(n)。
 

1.2.2 插入

//在线性表L中第i个位置插入元素e

    //判断插入位置i是否合法

    //判断顺序表的存储空间是否已满

    //将第n至第i位元素依次向后移动一个位置

    //将要插入的元素e放入第i个位置

    //表长加1,插入成功返回true

//在线性表L中第i个位置插入元素e
bool ListInsert_Sq(SqList &L, int i, ElemType e)
{
    //判断插入位置i是否合法
    if( i<1 || i>L.length+1 )
        return false;
    //判断顺序表的存储空间是否已满
    if( L.length == MaxSize )
        return false;
    //将第n至第i位元素依次向后移动一个位置
    for(int j = L.length; j>=i; j--)
        L.date[j] = L.date[j-1]; 
    //将要插入的元素e放入第i个位置
    L.date[i] = e;
    //表长加1,插入成功返回true
    L.length++;
    return true;
}

 
算法平均时间复杂度为O(n)------平均移动次数
 

1.2.3 删除

//删除第i个节点,将被删除元素赋值给引用变量e

    //判断删除元素位置i是否合法

    //将欲删除元素保留在e中

    //将第i+1至n位的元素依次向前移动一个位置

    //表长+1,删除成功返回true
//删除第i个节点,将被删除元素赋值给引用变量e
bool ListDelete_Sq(SqList &L, int i, ElemType &e)
{
    //判断删除元素位置i是否合法
    if(i < 1 || i > L.length)
        return false;
    //将欲删除元素保留在e中
    e = L.date[i]
    //将第i+1至n位的元素依次向前移动一个位置
    for(int j = i; j < L.length; j++)
        L.date[j-1] = L.date[j];
    //表长-1,删除成功返回true
    L.length--;
    return true;
}

 
算法平均时间复杂度为O(n)------平均移动次数
顺序表的空间复杂度S(n)=O(1),没有占用辅助空间。
 

1.3 题解

1.3.1选择

001.顺序表的插入算法中,当n个空间已满时,可再申请增加分配m个空间=需要申请n+m个
连续的存储空间。

2.链式表示

单向链表:只有一个指向后继节点的指针域。
双向链表:有两个指针域,一个指向前驱,一个指向后继。
循环链表:首尾相接

头指针→头结点首元结点
p永远是头结点p=L→next;

如何表示空表?
	答:头结点指针域为空。
在链表中设置头结点有什么好处?
	答:1.便于首元结点的处理;
	   2.便于空表和非空表的统一处理。
头结点的数据域内装的是什么?
	答:头结点数据域可以为空,也可以存放线性表长度等附加信息
	但是此节点不能计入链表长度值。

2.1 单链表

2.1.1 定义

单链表是由表头唯一确定,因此单链表可以用头指针的名字来命名。
若头指针名为L,则把链表称为L。

typedef struct LNode{
    ElemType data;      //数据域
    struct LNode *next; //指针域
}LNode, *LinkList;

//初始化,构造一个空表
bool Init_List(LinkList &L)
{
	//生成新结点做头结点,头指针指向头结点
	L = new LNode;
	//头结点的指针域置为空
	L->next = NULL;
	return true;
}
LNode *p = LinkList p;

 

2.1.2 查找

//根据指定数据获取数据所在的位置
LNode *LocateElem_List(LinkList &L, ElemType e)
{
    //从第一个节点起,依次和e做比较
    LNode *p = L->next;
    while(p != NULL && p->data != e)
    {
        p = p->next;
    }

    //如果找到一个和e相等的数据元素,返回其在链表中的位置;否则返回NULL
    return p;
}

 
查找算法时间复杂度为O(n)
 

2.1.3 插入

顺序不能乱:①s→next=p→next;②p→next=s

//将值为x的新节点插入到单链表的第i个位置上
bool Insert_List(LinkList &L, int i, ElemType x)
{
    LNode *p = L;
    int j = 0;
    //找到 a(i-1)的存储位置p
    while(p && j < i-1)
    {
        p = p->next;
        j++;
    }

    //检查插入位置的合法性
    if(!p || j > i-1)
        return false;

    //生成一个新结点*s
    s = new LNode;
    //将新结点*s的数据域置为x
    s->data = x;
    //新结点*s的指针域指向结点a(i)
    s->next = p->next;
    //令结点a(i-1)的指针域指向新结点*s
    p->next = s;

    return true;
}

 
查找算法时间复杂度为O(n)
前插操作同理后在交换数据域的值
 

2.1.4 删除

//删除第i个结点,把删除结点的值保存在e中
bool Delete_List(LinkList &L, int i, ElemType &e)
{
    LNode *p = L;
    int j = 0;

    //找到a(i-1)存储位置p
    while(p && j < i-1)
    {
        p = p->next;
        j++;
    }
    //临时保存结点a(i)的地址在q中,以备释放
    LNode *q = p->next;
    //令p->next指向a(i)的后继结点
    p->next = q->next;
    //将a(i)的值保留在e中
    e = q->data;
    //释放a(i)的空间
    delete q;

    return true;
}

 
查找算法时间复杂度为O(n)
 

2.1.5 单链表的建立

前插法:倒放
尾插法:正放

 
 

2.2 双向链表

2.2.1 定义

typedef struct DNode{
    ElemType data;          //数据域
    struct DNode *prior;    //前驱指针
    struct DNode *next;     //后继指针
}DNode, *DLinkList;

双向链表的按值查找和按序查找与单链表相同;
插入和删除不同,需要对前驱指针做出修改。
 
 

2.2.2 插入

//将值为x的新节点插入到双向链表的第i个位置上
bool Insert_DList(DLinkList &L, int i, ElemType e)
{
    //找到 a(i)的存储位置p

    //生成一个新结点*s
    //将新结点*s的数据域置为x

    //顺序不能乱,先赋值新结点*s的指针
    s->prior = p->prior;
    p->prior->next = s;

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

 
 

2.2.3 删除

//删除第i个结点,把删除结点的值保存在e中
bool Delete_DList(DLinkList &L, int i, ElemType &e)
{
    //找到 a(i)的存储位置p--today

    //yesterday的后继指针指向tomorrow
    p->prior->next = p->next;
    //tomorrow的前驱指针指向yesterday
    p->next->prior = p->prior;
    delete p;
}

 
 

2.3 循环链表

循环链表可以从表中任意位置开始遍历。
 
 


3.总结

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

BUPT_bo

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

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

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

打赏作者

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

抵扣说明:

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

余额充值