数据结构基础与线性表

3,692 阅读6分钟

数据结构核心名词解释

以下名称解释摘自《算法与数据结构》严蔚敏版。

数据(Data)

是客观事物的符号表示。在计算机科学中指的是所有能输入到计算机中并被计算机程序处理的符号的总称。

数据元素(Data Element)

数据元素是数据的基本单位,在程序中通常作为一个整体来进行考虑和处理。 一个数据元素可有若干个数据项(Data Item)组成。

数据项(Data Item)

数据项是数据不可分割的最小单位。数据项是对客观事物某一方面特性的数据描述。

数据对象(Data Object)

是性质相同的数据元素的集合,是数据的一个子集。

数据结构(Data Structure)

是指相互之间具有(存在)一定联系(关系)的数据元素的集合。元素之间的相互联系(关系)称为逻辑结构。数据元素之间的逻辑结构有四种基本类型。

逻辑结构与物理结构

逻辑结构

数据元素之间的关系可以是元素之间代表某种含义的自然关系,也可以是为处理问题方便而人为定义的关系,这种自然或人为定义的“关系”称为数据元素之间的逻辑关系,相应的结构称为逻辑结构。 逻辑结构有四种基本类型:

  1. 集合,结构中的数据元素除了”同属于同一个集合“外,没有其他关系。
  2. 线性结构,结构中的数据元素之间存在一对一的关系。
  3. 树形结构,结构中的数据元素之间存在一对多的关系。
  4. 图状结构或网状关系,结构中的数据元素之间存在多对多的关系。

物理结构

物理结构是指数据逻辑结构在计算机中的存储形式,一般有三种。

  1. 顺序存储结构,例如线性表。
  2. 链式存储结构,如树。
  3. 复合存储结构,如图。

算法

算法是对特定问题求解方法(步骤)的一种描述,是指令的有限序列,其中每一条指令表示一个或多个操作。

算法的特性

  • 有穷性:一个算法必须总是在执行有穷步骤之后结束,且每一步骤都在有穷时间内完成。
  • 确定性:算法中的每一条指令必须有确切的含义。不存在二义性。且算法只有一个入口和出口。
  • 可行性:一个算法是能行的。即算法描述的操作都可以通过已经实现的基本运算执行有限次来实现。
  • 输入:一个算法有零个或者多个输入,这些输入取自于某个特定的对象集合。
  • 输出:一个算法有一个或多个输出,这些输出是同输出有着某些特定关系的量。

算法设计要求

评价一个好的算法有以下几个标准:

  • 正确性:算法应该满足具体问题的需求。
  • 可读性:算法应该容易供人阅读和交流。可读性好的算法有助于对算法的理解和修改。
  • 健壮性:算法应该有容错处理。当输入非法或者错误数据时,算法能适当的做出反应或者处理,而不是产生莫名其妙的输出结果。
  • 通用性:算法应具有一般性,即算法的处理结果对于一般的数据集合都成立。
  • 效率与存储量需求:效率指的是算法执行的时间;存储量需求指算法执行过程中所需要的最大存储空间。一般与问题的规模有关。

算法效率衡量方法

算法执行时间虚通过依据该算法编制的程序在计算机上运行所消耗的时间来度量,也就是时间复杂度

时间复杂度

算法中基本操作重复执行的次数是问题规模n的某个函数,其时间度量记作T(n)=O(f(n)),称作算法的渐近时间复杂度,简称时间复杂度。一般地,常用最深层循环内的语句中的原操作的执行频度(重复执行的次数)来表示。 常用的时间复杂度的大小关系为:

image.png

image.png

空间复杂度

空间复杂度:是指算法编写成程序后,在计算机中运行时所需存储空间的大小的度量。记作:S(n)=O(f(n))。其中n为问题的规模。例如:

image.png

线性表

线性表(Linear List):是由n(n>=0)个元素(结点)a1,a2……an组成的有限序列。该序列中的所有结点具有相同的数据类型。其中数据元素的个数n称为线性表的长度。

  • 当n=0时,称为空表。
  • 当n>0时,将非空线性表记作:(a1,a2……an),a1称为线性表的第一个(首)结点,an称为线性表的最后一个(尾)结点。

顺序存储

把线性表的结点按逻辑顺序依次存放在一组地址连续的存储单元里。用这种方法存储的线性表简称顺序表。

顺序存储的特点

  • 线性表的逻辑顺序与物理顺序一致;
  • 数据元素之间的关系是以元素在计算机内“物理位置相邻”来体现。

image.png

顺序表的基本操作

顺序存储结构中,很容易实现线性表的一些操作:初始化、赋值、查找、修改、插入、删除、求长度等。

  • 顺序表的初始化
Status Init_SqList(SqList *L){
    L->elem_array = (ElemType*)malloc(MAX_SIZE*sizeof(ElemType));
    if(!L->elem_array){
        return ERROR;
    }else{
        L->Length = 0;
        return OK;
    }
}

直接进行malloc关键字的内存空间开辟。

  • 顺序表的插入
Status Insert_SqList(Sqlist *L, int i, ElemType e){
    int j;
    if(i<0||i>L->Length-1) return ERROR;
    if(L->Length >= MAX_SIZE){
        printf("线性表溢出!");
        return ERROR;
    }
    for(j= L->Length;j>=i-1;j--){
        L->Elem_array[j+1] = L->Elem_array[j];
    }
    L->Elem_array[i-1] = e;
    L->Length++;
    return OK;
}

步骤实现拆分:

  1. 将线性表L中的第i个至第n个结点后移一个位置。
  2. 将结点e插入到结点a[i-1]之后。
  3. 线性表长度加1。
  • 线性表的删除
ElemType Delete_SqList(Sqlist *L,int i){
    int l;
    ElemType x;
    if(L->length == 0){
        printf("线性表L为空");
        return ERROR;
    }else if(i<1||i>L->length){
        printf("要删除的数据元素不存在");
        return ERROR;
    }else{
        //要删除的结点的值 保存
        x = L->Elem_array[i-1];
        for(k = i; k<L->Lenght;k++){
            L->Elem_array[k-1] = L->Elem_array[k];
            L->length--;
            return(x);
        }
    }
}

步骤解析:

  1. 将线性表L中的第i+1个至第n个结点依次向前移动一个位置。
  2. 线性表长度减1。

链式存储

用一组任意的存储单元存储线性表中的数据元素。用这种方法存储的线性表简称线性链表

链式存储的特点

存储链表中结点的一组任意的存储单元可以是连续的,也可以是不连续的,甚至是分布在内存中的任意位置上的。链表中的逻辑顺序和物理顺序不一定相同。

image.png

本篇主要介绍了一些基本概念,下一篇会对链表进行详细的介绍和一些基本的操作进行算法实现。