线性表的基本操作

  在粗略学习一遍数据结构之后,压根就没有搞懂其中的逻辑,后来了明白学习数据结构的重要性,打算再利用一大段空闲时间重新拾起数据结构的学习。还站在IT行业门口的我,打算一步一步爬进去,跪着欣赏大佬的笔记和心得。对于数据结构初学者们来说,可能对你们有所帮助,如果有幸得到大佬的指点,也是在下吉人天相啊。

 

线性表的一些基本操作(同时补充下部分功能实现的逻辑和原理):

  1. 构造线性表结构  相当于C语言中的结构体,把实例的结构抽取、打框、定义类型、限制范围,最后取上别名
  2. 初始化线性表    对定义的值赋初值
  3. 销毁和清空线性表  销毁直接用到C++中的delete方法,快准狠;清空就是把线性表的长度直接赋值为0,长度为0,即是没有数据记录
  4. 求线性表长度  结构中就有存放长度的参数,直接访问就行了
  5. 判断线性表是否为空       即是判断长度为不为0,0就是空,非0就是表中有值
  6. 取值、查找、插入、删除 (下面代码直接体现逻辑)

 

代码采用的是C语言和一点C++语法,只展示了功能代码(有部分注释),main()就不再展示。

#include <stdio.h>
#include <stdlib.h>     // 给表分配内存,所需该头文件
#define MAXSIZE 100     线性表最大长度

补充:下面的宏定义是操作算法中用到的预定义常量和类型

   表示函数结果状态

#define TRUE 1
#define FALSE 0
#define OK 1         
#define ERROR 0      // 错误
#define INFEASIBLE -1  // 不可行
#define OVERFLOW -2  // 溢出

typedef int Status;  // Status是函数的类型,其值是函数返回结果的类型,此处定义为int型(后面用来返回地址下标)
typedef char ElemType;  // 定义线性表中存放数据的类型为 char型

// 构造线性表的存储结构
typedef struct{
ElemType elme[MAXSIZE];  // ElemType上面定义的类型     elem可看做线性表基地址(首地址)
int length;  // 存放长度
}SqList;  //结构名

// 构造一个空的线性表 -> 初始化线性表  在此实例化了L

Status InitList_Sq(SqList &L)
{
L.elme = new ElemType[MAXSIZE];  // 给L分配内存空间(C++方法)
if(!L.elme) exit(OVERFLOW);  // 此处为异常处理,分配成功,L为空表,分配不成功,L非空。OVERFLOW存储分配失败
L.length = 0;   // 赋初值,空表长度为0
return OK;  // 返回结果   对应该函数体的返回类型Status -> int型
}// InitList_Sq

// 销毁线性表
void DestroyList(SqList &L)
{
if(L.elme) delete L.elme;  // C++方法  delete
}//DestroyList

// 将L重置为空表
void ClearList(SqList &L)
{
L.length = 0;  // 长度设为0
}//ClearList

// 返回线性表的长度
int GetLength(SqList L)
{
return (L.length);  // 取长度参数值
}// GetLength

// 判断线性表是否为空
int IsEmpty(SqList L)
{
if(L.length == 1) return 1;
else return 0;    // 取出表长度值进行判断
}//IsEmpty

// 取值
int GetElem(SqList L,int i,ElemType &e)
{
if(i<1 || i>L.length) return ERROR;  // 判断位置i是否合法,由于线性表是有限序列,所以只能去存在的值,即第1个元素到最后1个元素之间的值,否则无效
e = L.length[i-1];  // 将位置i的值赋给存放结果的e
return OK;  // 返回操作结果(是否成功)
}//GetElem

// 查找
int LocateElem(SqList L,ElemType e)
{
for(i=0;i<L.length;i++)
if(L.elme[i] == e) return i+1;  // 对应下标的值进行判断,返回下标对应的值        i是物理地址(下标),i+1是逻辑地址(值)
return 0;
}//LocateElem

// 插入
Status ListInsert_Sq(SqList &L,int i,ElemType e)
{
if(i<1 || i>L.length+1) return ERROR;  // 判断合法性
if(L.length == MAXSIZE) return OVERFLOW;  // 判断表中是否满了,由于线性表的大小是不可更改的,所以在满了的情况下是不能再插入其他值,否则溢出
for(j=L.length-1;j>=i-1;j--)  // 从最后一个元素开始,一个个往后移,直至空出待插入的位置
  L.elme[j+1] = L.elme[j];  // 将前面1个元素移到后面的位置
L.elme[i-1]=e;  // 空出的位置给e
L.length++;  // 插入后长度+1
return OK;
}//ListInsert_Sq

// 删除
Ststus ListDelete_Sq(SqList &L,int i)
{
if(i<1 || i>L.length) return ERROR;
for(j=i;j<=L.length-1;j++)  // 从待删除元素后面1个开始到最后,一个个往前移
  L.elme[j-1] = L.elme[j];  // 直接挤掉待删除元素
L.length--;  // 删除1个元素后,长度-1
return OK;
}//ListDelete_Sq

 

 补充1:

  有人可能有疑问了,为什么形参中,有的是&L,而有的是L呢?

  &在C++中表示引用,所以&L使用的是引用传参。引用传参是直接把线性表的地址传过去进行操作,可直接修改线性表L的值,在初始化清空、销毁、插入、删除等操作中,都得对L进行修改(即重新赋值、添加删除元素)。在函数没有用到&L(即传参采用L)时,表示我只要线性表L当中的值,我并不需要线性表L为我修改任何值,调用时L是怎样的,返回到main函数就还是什么样的。

  那为什么不采用指针而是采用引用方法呢?C语言中的指针,只要是接触过的都知道,指针指来指去的看着容易乱逻辑,且不易阅读、调试难、容错高,所以有更好用、更方便的,为啥不用呢。

补充2:

  上述算法中,时间复杂度O(n),空间复杂度O(1)

补充3:

  用C语言分配内存 

  SqList L;

  L.elem=(ElemType *)malloc(sizeof(ElemType)*MAXSIZE);

  malloc()分配内存     free()释放内存

    用C++分配、释放内存 

  分配:int *L = new int;    或     int *L = new int(10)

  释放:delete L;

上一篇:LinuxC——1.文件读写


下一篇:数据结构C++实现——线性表之顺序表(静态分配)