数据结构之线性表的实现

线性表的定义

在生活中其实处处可见线性表的例子。比如一个班级的小朋友,一个跟着一个排着队,有一个打头,有一个收尾,当中的小朋友 每一个都知道他前面一个是谁,他后面一个是谁,这样如同有一根线把他们串联起来 了。 就可以称之为线性表。

所以线性表的定义为:零个或多个数据元素的有限序列。

首先它是一个序列。 也就是说,元素之间是有顺序的,若元素存在多个,则第一 个元素无前驱,最后一个元素无后继,其他每个元素都有且只有一个前驱和后继。 然后,线性表强调是有限的,小朋友班级人数是有限的,元素个数当然也是有限的。

线性表的抽象数据类型

那么定义好的线性表应该具有哪些操作呢?还是以前面排好队的小朋友举例子,我们可以知道这个队伍的长度,也可以找出队伍里的某个小朋友,有时我们还需要知道队伍里有没有一个叫小明的同学,这种查找某个元素是否存在也是线性表的必要操作。对于一个幼儿园来说,加入一个新的小朋友到队列中,或因某个小朋友生病,需要移除某个位置,也是很正常的情况,因此对于一个线性表来说,插入数据和删除数据都是必须的操作。所以我们可以定义这样一个线性表的抽象数据类型。

类型名称:线性表(List)
数据对象集:线性表是 n (≥0)个元素构成的有序序列( a1, a2, ...,an )
操作集:线性表L List,整数i表示位置,元素X ? ElementType,
线性表基本操作主要有:
1、List MakeEmpty():初始化一个空线性表L;
2、ElementType GetElem( int K, List L ):根据位序K,返回相应元素 ;
3、int Find( ElementType X, List L ):在线性表L中查找X的第一次出现位置;
4、void Insert( ElementType X, int i, List L):在位序i前插入一个新元素X;
5、void Delete( int  i, List L ):删除指定位序i的元素;
6、int Length( List L ):返回线性表L的长度n

线性表的存储结构

线性表这种有限序列的逻辑结构我们怎样在计算机中以物理形式存储起来呢?我们有两种实现方式:顺序存储和链式存储。

线性表的顺序存储结构

线性表的顺序存储结构,指的是用一段地址连续的存储单元依次存储线性表的数据元素。

#include<stdio.h>
//宏定义
#define MAXSIZE 50    //存储空间初始量分配
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
typedef int Status;
typedef int ElemType;//定义int类型的别名为ElemType

//初始化一个线性表结构体
typedef struct {
    ElemType data[MAXSIZE];//数组存储数据元素,最大值为MAXSIZE
    int length;//线性表当前长度
}SqList;

//获取线性表L中的第i个元素,并传给变量e,
Status GetElem(SqList L,int i,*e){
    if(L.length==0 || i<1 || i>L.length){
        return ERROR;
    }
    *e = L.data[i-1];
    return OK;
}

//在L中的第i个位置插入一个元素e
Status InsertList(SqList *L,int i,ElemType e){
    //SqList *L;定义一个指向线性表地址的指针变量L
    int k;
    if(L->length==MAXSIZE){
        return ERROR;//线性表已满
    }
    if(i<1 || i>L->length){
        return ERROR;//插入的位置不对
    }
    for(k=L->length-1;k>=i-1;k--){
        L->data[k+1] = L->length[k];
    }
    L->length[i-1]=e;//将新元素插入
    L->length++;//线性表长度加1
    return OK;
} 

//删除L中的第i个元素,并用变量e返回其值
Status  ListDlelte(SqList *L,int i,ElemType *e){
    int k;
    if(L->length == 0 || L->length == MAXSIZE){    //线性表为空或已满
        return ERROR;
    }
    if(i<1 || i>L->length){
        return ERROR;
    }
    *e = L->data[i-1];
    for(k=i;k>L->length;k++){
        L->data[k-1] = L->data[k];
    }
    L->length--;
    return OK;
}

顺序存储的优缺点及应用场景

线性表的顺序存储结构,在读数据时,不管是哪个位置,时间复杂度都是 0(1); 而插入或删除时,时间复杂度都是 O(n)。这就说明 ,它比较适合元 素个数不大变化,而更多是存取数据的应用。顺序存储的优缺点有。

优点  缺点
无须为表示表中元素之 间的逻辑关系而增加额 外的存储空间  插入和删除需要移动大量元素
可以快速的存取表中任意位置的元素 当线性表长度变化较大时,难以确定存储空间的容量,造成存储空间的碎片

既然顺序存储因为其插入和删除元素需要移动大量的元素而造成时间性能上的浪费。那么有没有一种存储结构能弥补顺序存储结构的缺点呢。当然是有的,就是我们接下来要讲的链式存储结构。

线性表的链式存储

和顺序存储不同的是,链式存储不需要向顺序存储那样开辟一块连续的存储空间来存储线性表元素,而是分散的插入到空闲的内存空间中。这样的话,前面的元素如果找到后面的元素就需要知道后一个元素的地址。因此链式存储的线性表结点就由两部分信息组成(存储数据元素信息的数据域和存储后继结点地址的指针域)。链表中的每个结点都存有一个指针域,因此也称作单链表。

#include<stdio.h>
typedef int ElemType
typedef int Status
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

/* 单链表结点存储结构 */
typedef struct Node{
    ElemType data;    //定义一个整型变量data
    struct Node *next;//定义一个结构体的指针变量
}Node;

单链表的结点定义好了,那么我们如何来遍历单链表的每一个结点元素呢?

既然元素结点的指针域存储了后继元素的地址,这样的话我们就可以定义一个指针变量来遍历所有的结点元素。

typedef struct Node *LinkList;    //定义指向单链表结点结构的指针变量,别名为LinkList

我们 假设p 是指向钱性表第 i 个元素的指针,则该结点 aj 的数据域 我们可以用 p->由回 来表示, p->由恒的值是一个数据元素,结点 aj 的指针域可以用 p->next 来表示, p->next 的值是一个指针。 p->next 指向谁呢? 当然是指向第 i+l 个 元素,即指向 ai+1 的指针。

所以线性表的链表操作定义为

//获取单链表中的第i个元素
Status GetElem(LinkList L,int i,ElemType *e){
    int j;
    LinkList p;    //声明一个结构体指针变量p
    p = L->next;//让p指向链表L的第一个节点
    j = 1;    //j为计数器
    while(p && j<i){
        p = p->next;    //让p指向下一个节点
        j++;
    }
    if(!p || j>i){
        return ERROR;
    }
    *e = p->data;
    return OK;

}

//在L中第i个位置之前插入新的数据元素e,L的长度增加1
Status ListInsert(LinkList *L,int i,ElemType e){
    int j;
    LinkList p,s;
    p = *L;//指针变量p的作用是遍历单链表
    j = 1;
    while(p && j<i){    //寻找第i个节点
        p = p->next;
        j++;
    }
    if(!p || j>i){
        return ERROR;
    }
    s = (LinkList)malloc(sizeof(Node));//创建一个存放指针变量的新结点
    s->data = e;
    s->next = p->next;
    p->next = s;
    *L->length++;
    return OK;
}

//删除L中的第i个数据元素,并用e返回其值, L的长度减1
Status ListDelete(LinkList *L,int i,ElemType *e){
    int j;
    LinkList p,q;
    p = *L;
    j = 1;
    while(p->next && j<i){    //遍历寻找第i个元素
        p = p->next;
        j++;
    }
    if(!(p->next) || j>i){
        return ERROR;    //第i个元素不存在
    }
    q = p->next;
    p->next = q->next;
    *e = q->data;
    *L->length--;
    free(q);

    return OK;
}

链式存储的优缺点及应用场景

线性表的链式存储结构,在读数据时,由于后继元素只能通过前驱元素的指针来访问,所以时间复杂度是 O(n); 而插入或删除时,要先遍历再插入或删除,遍历的复杂度为O(n),插入或删除的时间复杂度是 O(1)。这就说明 ,它比较适合元需要频繁插入或删除元素的应用。

单链表结构与顺序存储结构对比

  顺序存储 链式存储
查找(时间性能) O(1) O(n)
插入和删除(时间性能) 顺序存储结构需要移动表长一半的元素, 时间为O(n) 
单链表在找出某位置的指针后,插入和删除间仅为O(1)

空间性能 服序存储结构需要预先分配内存,分大了浪费, 分小了易发生上溢 
单链表不需要预先分配存储空间,只要有就可以分配, 元素个数也不受限制

原文地址:https://www.cnblogs.com/yuliangbin/p/8761658.html

时间: 2024-10-10 20:08:46

数据结构之线性表的实现的相关文章

自学数据结构——顺序线性表

胡乱写了一些代码 /* ============================================================================ Name : sqlist.c Author :codecup Version : Copyright : Your copyright notice Description : Hello World in C, Ansi-style ==========================================

软考之路--数据结构之线性表

数据就是数值,也就是我们通过观察.实验或计算得出的结果.数据有很多种,最简单的就是数字.数据也可以是文字.图像.声音等.数据可以用于科学研究.设计.查证等.结构,组成整体的各部分的搭配和安排,两者完美结合在一起,我们这样需要重新认识她,对她重新审视与定义:数据结构是程序设计的重要理论和技术基础,她所讨论的内容和技术,对从事软件项目的开发有重要作用,通过学习数据结构,我们学会从问题出发,分析和研究计算机加工的数据的特性,以便为应用所设计的数据悬着适当的逻辑结构.存储结构及其相应的操作方法,为提高应

[笔记]python数据结构之线性表:linkedlist链表,stack栈,queue队列

python数据结构之线性表 python内置了很多高级数据结构,list,dict,tuple,string,set等,在使用的时候十分舒心.但是,如果从一个初学者的角度利用python学习数据结构时,这些高级的数据结构可能给我们以迷惑. 比如,使用list实现queue的时候,入队操作append()时间复杂度可以认为是O(1),但是,出队操作pop(0)的时间复杂度就是O(n). 如果是想利用python学学数据结构的话,我觉得还是自己实现一遍基本的数据结构为好. 1.链表 在这里,我想使

自学数据结构——顺序线性表2

1 /* 2 ============================================================================ 3 Name : sqlist.c 4 Author : codecup 5 Version : 6 Copyright : Your copyright notice 7 Description : Hello World in C, Ansi-style 8 ==================================

数据结构:线性表插入一次删除一次的代码

#include <iostream> #include <cmath> #include <cstring> #include <algorithm> #include <stack> #include <queue> #include <cstdio> using namespace std; int insertsqlist(int weizhi,double charu,int *t,double b[]){   

数据结构之线性表(顺序存储结构)

小学生放学都是要按顺序排队的,一个接一个,每个小学生的前后位置是固定的,这样便于迅速清点. 其实这就是一个线性表,从这件事里我们就可以找到很多关于线性表的特性,如 1.线性表是一个序列,它是有顺序的(排队) 2.第一个元素无前驱,最后一个无后继,其他每个元素都有一个前驱和后继(一个接一个) 3.元素是有限的(小学生的个数是有限的) 4.数据类型都相同(都是小学生在排队) 说明白线性表示什么,下面我们直接看线性表的实现 线性表的实现分顺序存储结构和链式存储结构 顺序存储结构: #define LI

数据结构:线性表之单链表

线性表(亦作顺序表)是最基本.最简单.也是最常用的一种数据结构.线性表中数据元素之间的关系是一对一的关系,即除了第一个和最后一个数据元素之外,其它数据元素都是首尾相接的.线性表有两种存储结构: ①顺序存储结构,即存储单元在一段连续的地址上存储,常见的数组就是顺序存储结构的线性表: ②链式存储结构,即存储单元在不连续的地址上存储.因为其不连续性,除了要存数据元素信息(数据域)外,还要存储它后继元素(结点)的地址(指针域,链).学习链式结构最好将结点结构牢记于心,如下图: 链表的每个结点只含有一个指

数据结构之线性表

线性表是最简单最常用的一种数据结构,在生活中各个方面都有应用. 线性表的定义:线性表大多数情况下是除了第一个位置的数据元素只存在后继元素,最后一个位置的数据元素只存在前驱元素外,所有数据元素都存在前驱和后继的一个有限序列.举个简单的例子就是:字母表中除了 a 只存在后继 b,z 只存在前驱 y之外,剩余的所有字母全部都有前驱和后继.为什么是大多数情况下,是因为线性表的链式存储结构中除了单向链表,还有循环链表和双向链表. 线性表的存储结构:顺序存储(数组实现,需要预先分配连续的内存空间)和链式存储

浅谈数据结构之线性表顺序存储(一)

 首先,数据结构是由某一数据元素集合及该集合中所有数据元素之间的关系组成.具体来说,数据结构应当包含三方面的内容:(1).数据的逻辑结构:(2).数据的存储结构:(3).对数据所施加的操作.而数据的存储结构形式有两种:顺序存储与链式存储.在这里,先谈一谈线性表的顺序存储. 线性表:零个或多个数据元素的有限序列.第一,它是一个序列,也就是说,元素之间是有顺序的:第二,它是有限的,即元素个数是有限的.而线性表的顺序存储结构,说白了,就是在内存中找块地,通过占位的形式把一定的内存空间给占了,然后把相同

数据结构_线性表的顺序表示和链式表示

/********************************************************************************************************************/ 声明: (1)*.h文件是代码声明, *.cpp文件是代码实现; (2)一般头文件的内容有: ①类型声明; ②函数声明; ③枚举; ④常量; ⑤宏 (3)以下说明是为了方便代码文件的管理而设定的一些规则, 以后代码都会按照此规则编写: 1)Pubuse.h 是几