数据结构之线性表(顺序表、单链表、双链表)(一)

简介: 数据结构之线性表(顺序表、单链表、双链表)

1 线性表的基本概念


对于同一个线性表,其每一个数据元素的值虽然不同,但必须具有相同的数据类型;


数据元素之间具有一种线性的或“一对一”的逻辑关系;


第一个数据元素没有前驱,这个数据元素被称为开始节点;


最后一个数据元素没有后继,这个数据元素被称为终端节点;


除了第一个和最后一个数据元素外,其他数据元素有且仅有一个前驱和一个后继;


2 线性表抽象数据类型描述


基本操作如下:


线性表的置空操作clear():将一个已经存在的线性表置为空表;


线性表判空操作isEmpty():判断线性表是否为空,若为空,则返回true;否则,返回为false;


求线性表的长度操作length():求线性表中的数据元素的个数并返回其值;


取元素操作get(i):读取并返回线性表中的第i个数据元素的值。其中i的取值范围为0≤i≤length()-1;


插入操作insert(i,x):在线性表的第i个数据元素之前插入一个值为x的数据元素。其中i的取值范围为0≤i≤length()。当i=0时,在表头插入x;当i=length()时,在表尾插入x;


删除操作remove(i):删除并返回线性表中第i个数据元素。其中i的取值范围为0≤i≤length()-1;


查找操作indexOf(x):返回线性表中首次出现的指定的数据元素的位序号,若线性表中不包含此数据元素,则返回-1;


3 线性表的顺序表示和实现


3.1 顺序表的定义


所谓顺序表就是顺序存储的线性表。顺序存储是用一组地址连续的存储单元依次存放线性表中各个元素的存储结构。


3.2 顺序表的特点


在线性表中逻辑上相邻的数据元素,在物理存储上也是相邻的;


存储密度高,但要预先分配“足够应用”的存储空间,这可能会造成存储空间的浪费;


便于随机存储;


不便于插入和删除操作,这是因为在顺序表上进行的插入和删除操作会引起大量数据元素的移动;


3.3 顺序存储结构类的描述

image.png



顺序表的存储结构示意图


为了用C语言描述上图的顺序表,定义结构体SeqList如下:


typedef struct 
{
  DateType data[MAXSIZE];  /*数组存储数据元素*/
  int size;        /*线性表当前长度*/
}SqList;

【说明】:其中,DataType为数组元素(即数据元素)的数据类型,MaxSize表示数组的最大元素个数,list表示顺序表的数组成员,size表示顺序表中当前存储的数据元素个数成员,且必须满足条件size≤MaxSize,SeqList是结构体名。


3.4 顺序表操作的实现


在顺序存储结构下,线性表抽象数据类型定义的各个操作的具体实现方法如下:


初始化ListInitiate(L)
void ListInitiate(SeqList *L)    //初始化顺序表L
 {
     L->size = 0;  //定义初始化数据元素个数
 }

【说明】由于函数中要改变参数L的size域的值,所以参数L应设计为输出型参数,即参数L设计为SeqList的指针类型。否则,size域的修改值将不能带回去。


求当前数据元素个数ListLength(L)


int ListInitiate(SeqList L)    //返回顺序表L的当前数据元素个数
{
    return L.size;
}

插入数据元素ListInsert(L, i, x)


image.png


顺序表插入过程


代码实现:


int ListInsert(SqList *L, int i, DateType x)
{
  int k;
  if (L->size== MAXSIZE)  /*顺序线性表已满*/
  {
    printf("顺序表已满无法插入!\n");
    return 0;
  }
  if (i<1 || i>L->size)  /*i不在范围内*/
  {
    return 0;
  }
  if (i <= L->size-1)  /*插入位置不在表尾*/
  {
    //从后向前依次后移数据,为插入做准备
    for (k = L->size; k >=i-1 ; k--)
    {
      L->list[k] = L->list[k-1];
    }
  }
  L->list[i] = x;    //插入x
  L->size++;         //元素个数加1
  return 1;
}

【说明】:


如果线性表长度大于等于数组长度,抛出异常


如果插入位置不合理,抛出异常


从最后一个元素开始向前遍历到第i个位置,分别将它们都向后移动一个位置


从最后一个元素开始向前遍历到第i个位置,分别将它们都向后移动一个位置


表长加1


删除数据元素ListDelete(L, i, x)




顺序表删除过程


代码实现:


int ListDelete(SequenceList *L, int i, DateType *x) 
{
/*删除顺序表L中位置i(0 ≤ i ≤ size - 1)的数据元素值并存放到参数x中*/
/*删除成功返回1,删除失败返回0*/
    int j;
    if(L->size <= 0)
    {
        printf("顺序表已空无数据元素可删! \n");
        return 0;
    }
    else if(i < 0 || i > L->size-1)
    {
        printf("参数i不合法");
        return 0;
    }
    else
    {
        *x = L->list[i];  //保存删除的元素到参数x中
         //从i位置的后一位开始,依次往前移一位,直到最后
        for(j = i+1; j <= L->size-1; j++) 
        { 
          L->list[j-1] = L->list[j];
        }
        L->size--;        //数据元素个数减1
        return 1;
    }
}

【说明】:


如果为空表,抛出异常


如果删除位置不合理,抛出异常


从删除元素位置开始遍历到最后一个元素位置,分别将它们向前移动一个位置


表长减1


取数据元素ListGet(L, i, x)


/*取顺序表L中第i个数据元素的值存于x中,成功则返回1,失败返回0*/
int ListGet(SequenceList L, int i, DateType *x)
{
    if(i < 0 || i > L.size-1)
    {
        printf("参数i不合法! \n");
        return 0;
    }
    else
    {
        *x = L.list[i];
        return 1;
    }
}


相关文章
|
7月前
|
存储 机器学习/深度学习 算法
C 408—《数据结构》算法题基础篇—链表(下)
408考研——《数据结构》算法题基础篇之链表(下)。
191 30
|
7月前
|
存储 算法 C语言
C 408—《数据结构》算法题基础篇—链表(上)
408考研——《数据结构》算法题基础篇之链表(上)。
294 25
|
8月前
|
存储 算法 测试技术
【C++数据结构——线性表】求集合的并、交和差运算(头歌实践教学平台习题)【合集】
本任务要求编写程序求两个集合的并集、交集和差集。主要内容包括: 1. **单链表表示集合**:使用单链表存储集合元素,确保元素唯一且无序。 2. **求并集**:遍历两个集合,将所有不同元素加入新链表。 3. **求交集**:遍历集合A,检查元素是否在集合B中存在,若存在则加入结果链表。 4. **求差集**:遍历集合A,检查元素是否不在集合B中,若满足条件则加入结果链表。 通过C++代码实现上述操作,并提供测试用例验证结果。测试输入为两个集合的元素,输出为有序集合A、B,以及它们的并集、交集和差集。 示例测试输入: ``` a c e f a b d e h i ``` 预期输出:
213 7
|
8月前
|
机器学习/深度学习 存储 C++
【C++数据结构——线性表】单链表的基本运算(头歌实践教学平台习题)【合集】
本内容介绍了单链表的基本运算任务,涵盖线性表的基本概念、初始化、销毁、判定是否为空表、求长度、输出、求元素值、按元素值查找、插入和删除数据元素等操作。通过C++代码示例详细解释了顺序表和链表的实现方法,并提供了测试说明、通 - **任务描述**:实现单链表的基本运算。 - **相关知识**:包括线性表的概念、初始化、销毁、判断空表、求长度、输出、求元素值、查找、插入和删除等操作。 - **测试说明**:平台会对你编写的代码进行测试,提供测试输入和预期输出。 - **通关代码**:给出了完整的C++代码实现。 - **测试结果**:展示了测试通过后的预期输出结果。 开始你的任务吧,祝你成功!
320 5
|
10月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
860 9
|
10月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
216 59
|
3月前
|
编译器 C语言 C++
栈区的非法访问导致的死循环(x64)
这段内容主要分析了一段C语言代码在VS2022中形成死循环的原因,涉及栈区内存布局和数组越界问题。代码中`arr[15]`越界访问,修改了变量`i`的值,导致`for`循环条件始终为真,形成死循环。原因是VS2022栈区从低地址到高地址分配内存,`arr`数组与`i`相邻,`arr[15]`恰好覆盖`i`的地址。而在VS2019中,栈区先分配高地址再分配低地址,因此相同代码表现不同。这说明编译器对栈区内存分配顺序的实现差异会导致程序行为不一致,需避免数组越界以确保代码健壮性。
46 0
栈区的非法访问导致的死循环(x64)
232.用栈实现队列,225. 用队列实现栈
在232题中,通过两个栈(`stIn`和`stOut`)模拟队列的先入先出(FIFO)行为。`push`操作将元素压入`stIn`,`pop`和`peek`操作则通过将`stIn`的元素转移到`stOut`来实现队列的顺序访问。 225题则是利用单个队列(`que`)模拟栈的后入先出(LIFO)特性。通过多次调整队列头部元素的位置,确保弹出顺序符合栈的要求。`top`操作直接返回队列尾部元素,`empty`判断队列是否为空。 两题均仅使用基础数据结构操作,展示了栈与队列之间的转换逻辑。
|
8月前
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
332 77
|
7月前
|
算法 调度 C++
STL——栈和队列和优先队列
通过以上对栈、队列和优先队列的详细解释和示例,希望能帮助读者更好地理解和应用这些重要的数据结构。
153 11