#数据结构_2

简介: #数据结构_2

1.线性表:由n(n >= 0 )个数据特性相同的元素构成的有限序列成为线性表,元素个数n定义为线性表的长度,n=0时称为空表;


a,存在唯一被称为“第一个”的数据元素


b,存在唯一被称为“最后一个”的数据元素


c,除第一个外,结构中的每个数据元素均只有一个前驱


d,除最后一个外,结构中的每个数据元素均只有一个后继


2,线性表的顺序表示:是用一组地址连续的存储单元依次存储线性表的数据元素, 这种存储结构的线性表为顺序表逻辑上相邻的数据元素, 其物理次序也是相邻的


3,线性表链式存储结构:用一组任意的存储单元存储线性表的数据元素(单元可连续、可不连续),除了存储本身信息外,还需存储一个指示后继存储位置的信息,这两部分组成数据元素的结点(node),其中包括存储数据元素信息的 数据域 和 存储直接后继存储位置的 指针域 ,指针域中存储的信息称作 指针 或 链,n个结点链结成一个链表(线性表的链式存储结构),此链表的每个结点只包含一个指针域,故称 线性链表/单链表;


4.单链表


a.单链表初始化


i.构造一个空的链表


ii.生成新节点作为头节点,用头指针指向头结点


iii.头结点指针域置空

Status InitList(LinkList &L)
{
    L = new LNode;
    L->next = NULL;
    return ok;
}

b.取值:和顺序表不同,链表中逻辑相邻的节点并没有存储在物理相邻的单元中,只能从链表的首元结点出发,顺着链域next逐个结点向下访问;


i.用指针p指向首元结点,用j做计数器初始值赋为1;


ii.从首元结点开始依次顺着链域 next 向下访问,只要指向当前结点的指针 p 不为NULL, 并且没有到达序号为i的结点,则循环执行:


1.p指向下一个结点;


2.计数器j相应加1。


iii.退出循环时, 如果指针p为空, 或者计数器j>i, 说明指定的序号i值不合法; 否则取值成功, 此时j=i时,p所指的结点就 是要找的第i个结点;

/ /在带头结点的单链表L中根据序号i获取元素的值,用e返回L中第i个数据元素的值
Status GetElem(LinkList L, int i, ElemType &e)
{
    p = L->next;
    j = 1;
    while(p && j<i)
    {
        p = p->next;
        ++j;
    }
    if(!p || j>i)
    {
        return ERROR; 
    }
    e = p->data; 
    return OK;
}

c.查找


i.用指针p指向首元结点 ;


ii.从首元结点开始依次顺着链域next向下查找, 只要指向当前结点的指针p不为空, 并且p所指结点的数据域不等千给定值e, 则循环执行以下操作: p指向下一个结点 ;


ii.返回p,若查找成功,p此时即为结点的地址值,若查找失败,p的值即为NULL

LNode *LocateELem(LinkList L, Elemtype e) 
    p=L->next; 
    while(p && p->data!=e) 
        p=p->next; 
    return p; 
}

d.插入

i.查找结点a, 并由指针p指向该结点的前一结点

ii.生成一个新结点*s

iii.将新结点*s 的数据域置为 e

iv.将新结点*s 的指针域指向结点a

v.将结点*p 的指针域指向新结点*s

Status ListInsert(LinkList &L, int i, ElemType e)
{
    p = L;
    j = 0;
    while(p && (j<i-1))
    {
        p = p->next;
        ++j;
    }
    if(!p || j>i-1)
        return ERROR;
    s = new LNode;
    s->data = e;
    s->next = p->next;
    p->next = s;
    return OK;
}

e.删除

i.查找结点a并由指针p指向该结点的前一结点

ii.临时保存待删除结点a的地址在q中 ,以备释放

iii.将结点*p的指针域指向a的直接后继结点

iv释放结点a的空间

Status ListDelect(LinkList &L, int i, ElemType e)
{
    p = L;
    j = 0;
    while(p->next && j<i-1)
    {
        p = p->next;
        ++j;
    }
    if(!p->next || j>i-1)
        return ERROR;
    q = p->next;
    p->next = q->next;
    delect q;
    return OK;
}

f.前插法

i.创建一个只有头结点的空链表

ii.根据待创建链表元素个数n, 循环n次

iii.生成一个新结点*p

iv.输入元素值赋给新结点*p的数据域

v.将新结点*p插入到头结点之后

void CreateList_H(LinkList &L, int n)
{
    L = new LNode;
    L->next = NULL;
    for(int i = 0; i < n; i++)
    {
        p = new LNode;
        cin >> p->data;
        p->next = L->next;
        L->next = p;
    }
}

g.后插法

i.创建一个只有头结点的空链表

ii.尾指针r初始化, 指向头结点

iii.根据创建链表包括的元素个数n, 循环n次

1.生成一个新结点*p

2.输入元素值赋给新结点*p 的数据域

3.将新结点*p 插入到尾结点*r之后

4.尾指针r指向新的尾结点*p

void CreateList_R(LinkList &L, int n)
{
    L = new LNode;
    r = L;
    for(int i = 0; i < n; i++)
    {
        p = new LNode;
        cin >> p->data;
        p->next = NULL;
        r->next = p;
        r = p;
    }
}

5.循环链表:最后一个节点的指针域指向头节点,整个链表形成一个环,判别终止条件从指针域是否指向NULL 变为 是否指向L(头结点)

6.双向链表:在双向链表的结点中有两个指针域,一个指向直接后继,一个指向直接前驱;

typedef struct DuLNode
{
    ElemType data;    //数据域
    struct DuLNode *prior    //直接前驱
    struct DuLNode *next    //直接后继
}DuLNode, *DuLinkList;

a.双向链表的插入

//在双向链表L中第i个位置之前插入元素e
Status ListInsert_DuL(DuLinkList &L, int n, ElemType e)
{
    if (1 (p=GetElem_DuL (L, i)))     //在L中确定第i个元素的位置指针p
        return ERROR;                 //p为 NULL 时,第i个元素不存在
    s = new DuLNode; 
    s->data = e; 
    s->prior = p->prior;             //将结点*s插入L中
    p->prior->next = s; 
    s->next = p; 
    p->prior = s; 
    return OK; 
}

b.双向链表的删除

//删除双向链表L中的第i个元素
Status ListDelete_DuL(DuLinkList &L,int i) 
{
    if (!(p=GetElem_DuL(L, i)))     //在L中确定第i个元素的位置指针p
        return ERROR;                 //p为 NULL 时,第i个元素不存在
    p->prior->next = p->next;         //修改被删结点的前驱结点的后继指针
    p->next->prior = p->prior;         //修改被删结点的后继结点的前驱指针
    delete p;                         //释放被删结点的空间
    return OK;
}

7.空问性能


a.顺序表的存储空间必须预先分配,链表不需要为其预先分配空间,当线性表的长度变化较大,难以预估存储规模时,宜采用链表作为存储结构。


b.链表的每个结点除了设置数据域用来存储数据元素外,还要额外设置指针域,如果每个元素数据域占据的空间较小,则指针的结构性开销就占用了整个结点的大部分空间,当线性表的长度易于事先确定其大小时,宜采用顺序表作为存储结构。


8.时间性能


a.顺序表是由数组实现,指定任意一个位置序号i都可以接存取该位置上的元素;


b.链表是一种顺序存取结构,访问链表中第i个元素时,只能从表头开始依次向后遍历链表;


c.对于链表,在确定插入或删除的位置后只需要修改指针;


d.对于顺序表,进行插入或删除时,平均要移动表中近一半的结点,尤其是当每个结点的信息量较大时,移动结点的时间开销就相当可观;


e.对于频繁进行插入或删除操作的线性表,宜采用链表作为存储结构;很少做插入或删除时宜采用顺序表作为存储结构。

相关文章
|
6月前
|
存储 C++
c++数据结构
c++数据结构
47 0
|
存储 机器学习/深度学习 算法
进入数据结构的世界
进入数据结构的世界
|
1月前
|
存储 NoSQL 索引
【数据结构】数据结构学什么?
【数据结构】数据结构学什么?
37 5
|
1月前
|
消息中间件 缓存 调度
常见的8种数据结构
常见的数据结构包括数组、链表、队列、栈、树、堆、哈希表和图。
43 4
|
3月前
|
消息中间件 缓存 调度
常见的八种数据结构
常见的数据结构包括数组、链表、队列、栈、树、堆、哈希表和图,每种数据结构都有其特点
57 3
|
3月前
|
存储 JavaScript 前端开发
复杂数据结构
【8月更文挑战第25天】
31 0
|
6月前
|
存储 算法
数据结构
数据结构
46 2
|
存储 Java C++
总结数据结构-1
总结数据结构-1
41 0
|
存储 算法 搜索推荐
【BaseArray 数据结构】
【BaseArray 数据结构】
|
存储 算法
【数据结构】初识(下)
【数据结构】初识(下)
73 0