【数据结构】线性表(顺序存储和链式存储)两种方法,细节满满,保你学会(一)

简介: 【数据结构】线性表(顺序存储和链式存储)两种方法,细节满满,保你学会

⭐定义:

线性表(List):零个或多个数据元素的有限序列


⭐ 理解:

线性表,顾名思义,就是具有像线一样性质的表,元素之间是有顺序的,若元素存在多个,那么第一个元素没有前驱元素,最后一个元素没有后继元素,其他元素既有前驱元素又有后继元素


⭐存储方式 :

线性存储


链式存储


⭐顺序存储的优缺点:

优点:

1.表中数据元素可以根据序号 随机存取


2. 存储密度大,存储密度为1(存储密度是指一个结点中数据元素所占的存储单元和整个结点所占的存储单元之比)


缺点:

1.做插入、删除操作时,要移动大量元素,因此对很长的线性表操作效率低,插入和删除操作不方便;


2.要预先分配存储空间,预先估计过大,会导致存储空间浪费,估计过小,会造成数据溢出。


⭐链式存储的优缺点:

优点:

1.做插入、删除操作时,不用移动大量元素,相比线性存储方式方便;


2.不用预先分配存储空间。


缺点:

1.表中数据元素不可随机存取


2.存储密度小,存储密度小于1


⭐基本操作

✨顺序存储

🍔存储结构

#define maxsize 100
typedef struct{
  ElemType *elem;//由于这里不知道线性表的具体长度,所以这里就用了指针
                   //可以是elem[maxsize]
  int length;
}SqList;

其中ElemType可以改为其他的数据类型 ,比如

typedef int ElemType

length表示当前线性表中数据元素的个数,注意数组里面的下标是从0开始的,那么


a1->elem[0]; //注意,用数组表示


a2->elem[1];


a3->elem[2] ;


an->elem[length-1];


🎈初始化


🚕分配空间,建立空表,使空表长度为0


使用引用初始化

int InitList(SqList &L)
{
  L.elem=new ElemType[maxsize];
  if(!L.elem) return -1;      //内存分配失败
  L.length=0;           //空表长度为0
  return 1; 
}

使用指针初始化

int InitList(SqList* L)
{
  L->elem = new int[100];
  if (!L->elem) exit(overflow);
  L->length = 0;
  return OK;
}

🎈添加数字建立表

🚕向空表里面添加数字,从而建立线性表

使用引用

void InputList(SqList& L, int num)
{
  L.elem[k++] = num;
  L.length++;
}

使用指针

void InputList(SqList* L, int num)
{
  L->elem[k++] = num;
  L->length++;
}

🎈输出线性表里面的数

🚕输出线性表里面的数

使用引用

void OutputList(SqList& L)
{
  for (int i = 1; i <= L->length; i++)
  {
    cout << L.elem[i] << " ";
  }
}

使用指针

void OutputList(SqList *L)
{
  for (int i = 1; i <= L.length; i++)
  {
    cout << L->elem[i] << " ";
  }
}

🎈插入数字

🚕顺序存储插入数字,就是找到要插入的数字的位置,从这个位置开始的后面的所有的数字全都后移一位,这样子前面就回空出一个位置,就是要插入的数字的位置


使用引用

void ListInsert(SqList& L, int place, int num)
{
  L.length++;
  for (int i = L.length; i >= place; i--)
  {
    L.elem[i + 1] = L.elem[i];
  }
  L.elem[place] = num;
}

注意:这里是  i = L.length , 不是 i = L.length-1

你想一下,数组下标是从0开始的,所以整个表最后一个位置(L.elem[length])没有存数

这样把数组后移,到最后刚好可以空出一个位置来存需要插入的数

使用指针

void ListInsert(SqList *L, int place, int num)
{
  L->length++;
  for (int i = L->length; i >= place; i--)
  {
    L->elem[i + 1] = L->elem[i];
  }
  L->elem[place] = num;
}

🎈删除数字

🚕与插入数字类似,删除数字采用的是向前覆盖数字

使用引用

void ListDelete(SqList& L, int place)
{
  for (int i = place; i <= L.length; i++)
  {
    L.elem[i - 1] = L.elem[i];
  }
  L.length--;
}

使用指针

void ListDelete(SqList *L, int place)
{
  for (int i = place; i <= L->length; i++)
  {
    L->elem[i - 1] = L->elem[i];
  }
  L->length--;
}

🎈取出数字

🚕就是给出这个数字的位置,就是想当于给出了这个数字在数组里面的位置,然后直接根据这个位置取值

int GetElem(SqList L, int i, int& e)//int *e
{
  if ((i < 1) || (i > L.length)) return -1;
  e = L.elem[i];                  //*e=L.elem[i];
  return 1;
}
int GetElem(SqList *L, int i, int& e)
{
  if ((i < 1) || (i > L->length)) return -1;
  e = L->elem[i];
  return 1;
}

🎈置空

🚕直接L.length=0就可以了

(如果要返回线性表的长度,直接L.length即可)

😎完整代码1

#include<iostream>
using namespace std;
#define OK 1
#define overflow -1
int k=1;
typedef struct{
  int *elem;
  int length;
}SqList;
int InitList(SqList &L)
{
  L.elem=new int[100];
  if(!L.elem) exit(overflow);
  L.length=0;
  return OK;
}
//3
void InputList(SqList &L,int n)
{
  L.elem[k++]=n;
  L.length++;
}
//4
void OutputList(SqList &L)
{
  for(int i=1;i<=L.length;i++)
  {
    cout<<L.elem[i]<<" ";
  }
} 
//5
void ListInsert(SqList &L,int a,int b)
{
  L.length++;
  for(int i=L.length;i>=a;i--)
  {
    L.elem[i+1]=L.elem[i];
  }
  L.elem[a]=b;
}
//6   
 void ListDelete(SqList &L,int x)
 {
  for(int i=x;i<=L.length;i++)
  {
    L.elem[i-1]=L.elem[i];
   }  
  L.length--;
 }
 //7
 int GetElem(SqList L,int i,int &e)
 { 
  if((i<1)||(i>L.length)) return -1;
   e=L.elem[i];
   return OK;
 }
 //8
int ClearList(SqList L)
{
    L.length=0;
    return 1;
}
int main()
{
  SqList L;
  int s,e;
  InitList(L);
  if(InitList) cout<<"成功"<<endl;
  else cout<<"失败"<<endl;
  cout<<"0:退出程序"<<endl;
  cout<<"3:加入数"<<endl;
  cout<<"4:输出线性表里面的数"<<endl;
  cout<<"5:插入数"<<endl;
  cout<<"6:删除数"<<endl;
  cout<<"7:取出某个位置的数"<<endl;
  cout<<"8:置空"<<endl;
  cout<<endl;
  for(;;)
  {
    cout<<"请输入3~8之间的数,代表3~8题,0表示程序结束"<<endl;
    cin>>s;
    if(s==0) return 0;
    switch(s)
    {
    case 3:
      cout<<"请输入需要加入的数的个数:"<<endl;
      int n;
      cin>>n;
      cout<<"请输入需要加入的数:"<<endl;
      for(int i=1;i<=n;i++)
      {
        int t;
        cin>>t;
        InputList(L,t); 
      }
      break;
    case 4:
      OutputList(L);
      cout<<endl;
      break;
    case 5:
      for(int i=1;i<=2;i++)
      {
        cout<<"请输入插入的位置和插入的数是什么:"<<endl;
        int a,b;
        cin>>a>>b;
        ListInsert(L,a,b);
      }
      break;
    case 6:
      cout<<"请输入需要删除哪个位置的数:"<<endl;
      for(int i=1;i<=2;i++)
      {
        int aa;
        cin>>aa;
        ListDelete(L,aa);
      }
      break;  
    case 7:
      cout<<"请输入需要取出哪个位置的数:"<<endl;
      for(int i=1;i<=2;i++)
      {
        int a;
        cin>>a;
        GetElem(L,a,e);
        cout<<"第"<<a<<"个位置的数的值为:"<<e<<endl;
      }
      break;
    case 8:
      if (ClearList(L)) cout << "置空成功" << endl;
      else cout << "置空失败" << endl;
      break;
    }
  }
 } 

🚌小细节:什么时候使用引用,什么时候不使用引用

观察代码我们会发现,


有的是SqList L(没有使用引用)


有的是SqList &L(使用了引用)


这是为什么呢


原因:我们发现,使用引用的代码段里面都会有分配空间的操作,而没有使用引用的代码段里面就没有分配空间的操作


分配一段空间,使整个程序改变了,所以要使用引用,而如果不分配空间,那么就直接使用就行了,不需要引用


😎完整代码2  

#include<iostream>
using namespace std;
#define OK 1
#define overflow -1
int k = 1;
typedef struct {
  int* elem;
  int length;
}SqList;
int InitList(SqList* L)
{
  L->elem = new int[100];
  if (!L->elem) exit(overflow);
  L->length = 0;
  return OK;
}
//3
void InputList(SqList* L, int n)
{
  L->elem[k++] = n;
  L->length++;
}
//4
void OutputList(SqList* L)
{
  for (int i = 1; i <= L->length; i++)
  {
    cout << L->elem[i] << " ";
  }
}
//5
void ListInsert(SqList *L, int place, int num)
{
  L->length++;
  for (int i = L->length; i >= place; i--)
  {
    L->elem[i + 1] = L->elem[i];
  }
  L->elem[place] = num;
}
//6   
void ListDelete(SqList *L, int place)
{
  for (int i = place; i <= L->length; i++)
  {
    L->elem[i - 1] = L->elem[i];
  }
  L->length--;
}
//7
int GetElem(SqList L, int i, int& e)
{
  if ((i < 1) || (i > L.length)) return -1;
  e = L.elem[i];
  return OK;
}
//8
int ClearList(SqList *L)
{
  L->length=0;
    return 1;
}
int main()
{
  SqList L;
  int s, e;
  InitList(&L);
  if (InitList) cout << "成功" << endl;
  else cout << "失败" << endl;
  cout << "0:退出程序" << endl;
  cout << "3:加入数" << endl;
  cout << "4:输出线性表里面的数" << endl;
  cout << "5:插入数" << endl;
  cout << "6:删除数" << endl;
  cout << "7:取出某个位置的数" << endl;
  cout << "8:置空" << endl;
  cout << endl;
  for (;;)
  {
    cout << "请输入3~8之间的数,代表3~8题,0表示程序结束" << endl;
    cin >> s;
    if (s == 0) return 0;
    switch (s)
    {
    case 3:
      cout << "请输入需要加入的数的个数:" << endl;
      int n;
      cin >> n;
      cout << "请输入需要加入的数:" << endl;
      for (int i = 1; i <= n; i++)
      {
        int t;
        cin >> t;
        InputList(&L, t);
      }
      break;
    case 4:
      OutputList(&L);
      cout << endl;
      break;
    case 5:
      for (int i = 1; i <= 2; i++)
      {
        cout << "请输入插入的位置和插入的数是什么:" << endl;
        int a, b;
        cin >> a >> b;
        ListInsert(&L, a, b);
      }
      break;
    case 6:
      cout << "请输入需要删除哪个位置的数:" << endl;
      for (int i = 1; i <= 2; i++)
      {
        int aa;
        cin >> aa;
        ListDelete(&L, aa);
      }
      break;
    case 7:
      cout << "请输入需要取出哪个位置的数:" << endl;
      for (int i = 1; i <= 2; i++)
      {
        int a;
        cin >> a;
        GetElem(L, a, e);
        cout << "第" << a << "个位置的数的值为:" << e << endl;
      }
      break;
    case 8:
      if (ClearList(&L)) cout << "置空成功" << endl;
      else cout << "置空失败" << endl;
      break;
    }
  }
}
相关文章
|
2月前
|
机器学习/深度学习 算法 数据挖掘
K-means聚类算法是机器学习中常用的一种聚类方法,通过将数据集划分为K个簇来简化数据结构
K-means聚类算法是机器学习中常用的一种聚类方法,通过将数据集划分为K个簇来简化数据结构。本文介绍了K-means算法的基本原理,包括初始化、数据点分配与簇中心更新等步骤,以及如何在Python中实现该算法,最后讨论了其优缺点及应用场景。
146 4
|
1天前
|
存储 算法 测试技术
【C++数据结构——线性表】求集合的并、交和差运算(头歌实践教学平台习题)【合集】
本任务要求编写程序求两个集合的并集、交集和差集。主要内容包括: 1. **单链表表示集合**:使用单链表存储集合元素,确保元素唯一且无序。 2. **求并集**:遍历两个集合,将所有不同元素加入新链表。 3. **求交集**:遍历集合A,检查元素是否在集合B中存在,若存在则加入结果链表。 4. **求差集**:遍历集合A,检查元素是否不在集合B中,若满足条件则加入结果链表。 通过C++代码实现上述操作,并提供测试用例验证结果。测试输入为两个集合的元素,输出为有序集合A、B,以及它们的并集、交集和差集。 示例测试输入: ``` a c e f a b d e h i ``` 预期输出:
25 7
|
1天前
|
机器学习/深度学习 存储 C++
【C++数据结构——线性表】单链表的基本运算(头歌实践教学平台习题)【合集】
本内容介绍了单链表的基本运算任务,涵盖线性表的基本概念、初始化、销毁、判定是否为空表、求长度、输出、求元素值、按元素值查找、插入和删除数据元素等操作。通过C++代码示例详细解释了顺序表和链表的实现方法,并提供了测试说明、通 - **任务描述**:实现单链表的基本运算。 - **相关知识**:包括线性表的概念、初始化、销毁、判断空表、求长度、输出、求元素值、查找、插入和删除等操作。 - **测试说明**:平台会对你编写的代码进行测试,提供测试输入和预期输出。 - **通关代码**:给出了完整的C++代码实现。 - **测试结果**:展示了测试通过后的预期输出结果。 开始你的任务吧,祝你成功!
19 5
|
1天前
|
机器学习/深度学习 存储 C++
【C++数据结构——线性表】顺序表的基本运算(头歌实践教学平台习题)【合集】
本文档介绍了线性表的基本运算任务,涵盖顺序表和链表的初始化、销毁、判定是否为空、求长度、输出、查找元素、插入和删除元素等内容。通过C++代码示例详细展示了每一步骤的具体实现方法,并提供了测试说明和通关代码。 主要内容包括: - **任务描述**:实现顺序表的基本运算。 - **相关知识**:介绍线性表的基本概念及操作,如初始化、销毁、判定是否为空表等。 - **具体操作**:详述顺序表和链表的初始化、求长度、输出、查找、插入和删除元素的方法,并附有代码示例。 - **测试说明**:提供测试输入和预期输出,确保代码正确性。 - **通关代码**:给出完整的C++代码实现,帮助完成任务。 文档
19 5
|
2月前
|
算法 安全 搜索推荐
2024重生之回溯数据结构与算法系列学习之王道第2.3章节之线性表精题汇总二(5)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
IKU达人之数据结构与算法系列学习×单双链表精题详解、数据结构、C++、排序算法、java 、动态规划 你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
2月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
256 9
|
2月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
41 1
|
1天前
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
110 75
|
1天前
|
存储 C++ 索引
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
【数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】初始化队列、销毁队列、判断队列是否为空、进队列、出队列等。本关任务:编写一个程序实现环形队列的基本运算。(6)出队列序列:yzopq2*(5)依次进队列元素:opq2*(6)出队列序列:bcdef。(2)依次进队列元素:abc。(5)依次进队列元素:def。(2)依次进队列元素:xyz。开始你的任务吧,祝你成功!(4)出队一个元素a。(4)出队一个元素x。
24 13
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
|
1天前
|
存储 C语言 C++
【C++数据结构——栈与队列】链栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现链栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储整数,最大
24 9