线性表-顺序表和链式表概念及其代码实现【数据结构与算法】

    文章主要是对于数据结构与算法课程学习的读书记录。欢迎学习交流。
    [内容范围]第二章线性表-顺序表和链式表概念及其代码实现。

文章目录

  • 1 线性表的定义
  • 2 基于线性表的简单操作
    • 2.1 合并线性表
    • 2.2 合并有序表
  • 3 线性表的顺序存储结构(全)
    • 3.1 线性表的顺序存储基本概念
    • 3.2 顺序存储的C代码实现
      • 3.2.1 顺序存储表的定义
      • 3.2.2 初始化顺序存储表
      • 3.2.3 表中按照位置查找值
      • 3.2.4 表中按照值查找位置
      • 3.2.5 在指定位置插入元素
      • 3.2.6 删除指定位置的元素
    • 3.3 顺序存储结构存在的问题
  • 4 线性表的链式存储结构(全)
    • 4.1 线性表的链式存储的基本概念
    • 4.2 链式存储的C代码实现
      • 4.2.1 链式存储的类型定义
      • 4.2.2 变量的定义和实现
      • 4.2.3 单链表按位置查找值
      • 4.2.4 单链表按值查找位置
      • 4.2.5 单链表上的插入操作
      • 4.2.6 单链表上的删除操作
      • 4.2.7 单链表的创建及插入n个数据
  • 总结

1 线性表的定义

线性表: n个同类型数据元素的有限序列,记为:
L= (a1,a2,…,ai,…,an)
L为表名;
i为数据元素ai 在线性表中的位序;
n为线性表的表长; n=0 时称为空表;
数据元素之间的关系是:
ai-1领先于ai,ai领先于ai+1。
称ai-1是ai的直接前驱,ai+1是ai的直接后继,
除第一元素a1外,均有唯一的前驱;

2 基于线性表的简单操作

2.1 合并线性表

算法设计:
思想:从LB中逐一取出元素,判断元素是否存在LA中,若不在则将这个元素插入到LA中

//依次从LB中取出第i个数据元素:List_Retrieve(Lb, i, &elem) →elem
//判elem是否在LA中存在:List_Locate(La,elem,&j)
//若不存在,则将elem插入到LA中:List_Insert(La,1,elem)

Status List_Union (SqListPtr La, SqListPtr Lb){
     
ElemType elem; /* 存放从Lb中取出的元素*/
Status status; /*状态代码*/
int i, j, len = List_Size(Lb); /*len存放Lb的元素个数*/
for (i=1; i<=len; i++){
     
List_Retrieve(Lb, i, &elem); /*取出Lb中第i个数据元素*/
status = List_Locate(La,elem,&j); /*判它是否在La中*/
if(status!= success){
      /*如果不在*/
status = List_Insert(La,1,elem); /*插入到第一个位置*/
if(status!= success) break; /*插入失败则退出*/ }
else List_Add(La,j,1);/*La的第j个数据加1*/
}
return status;
}

2.2 合并有序表

问题:已知线性表La和Lb中的元素按照递增顺序排列,现要求将他们合并成一个新的线性表Lc,病似的Lc中元素也按照递增的顺序排列

思想:线性表Lc初始为空。依次扫描La和Lb中的元素,比较
当前元素的值,将较小值的元素插入Lc的表尾之后,如此反
复,直到一个线性表扫描完毕,然后将未完的那个线性表中
余下的元素逐个插入到Lc的表尾之后

Status List_Merge (SqListPtr La, SqListPtr Lb, SqListPtr Lc){
     
ElemType elem1, elem2; status = List_Init(Lc);
int i=1, j=1, k=1; /*i, j, k分别用于指示La, Lb, Lc中当前元素*/
int n = List_Size(La),m = List_Size(Lb);
while(i<=n && j<=m){
      /*两个表都还未处理完*/
List_Retrieve(La,i,&elem1); List_Retrieve(Lb,j,&elem2);
if(elem1<elem2){
      status = List_Insert(Lc,k,elem1); i=i+1; }
else{
      status = List_Insert(Lc,k,elem2); j=j+1; }
k=k+1;
}

Status List_Merge (SqListPtr La, SqListPtr Lb, SqListPtr Lc){
     
…….
while(i<=n){
      /*表La都还未处理完*/
List_Retrieve(La, i, &elem1);
status = List_Insert(Lc, k, elem1);
i=i+1; k=k+1; }
while(j<=m){
      /*表Lb都还未处理完*/
List_Retrieve(Lb, j, &elem2);
status = List_Insert(Lc, k, elem2);
j=j+1; k=k+1; }
return status;
}

3 线性表的顺序存储结构(全)

3.1 线性表的顺序存储基本概念

线性表-顺序表和链式表概念及其代码实现【数据结构与算法】_第1张图片
线性表-顺序表和链式表概念及其代码实现【数据结构与算法】_第2张图片

3.2 顺序存储的C代码实现

3.2.1 顺序存储表的定义

#define LIST_INIT_SIZE 100 //空间个数
#define LIST_INCREAMENT 10 //每次增加的空间个数
typedef int ElemType;//重新命名类型
typedef struct SqList//重新命名结构体
{
     
ElemType *elem;//一大片连续空间的首地址
int length; //长度 开始未知
int list_size;//个数 开始未知
}SqList, *Ptr;
typedef Ptr *SqlListPtr;

3.2.2 初始化顺序存储表

Status List_Init(SqListPtr L)
{
     
Status s = success;
L->list_size = LIST_INIT_SIZE;//宏定义的值
L->length = 0;//初始为0
L->elem = (ElemType *)malloc(sizeof(ElemType)*L->list_size);//开辟空间
if (L->elem == NULL)
s=fatal;
return s;
}

3.2.3 表中按照位置查找值

Status List_Retrival(SqListPtr L, int pos, ElemType *elem)
{
     
Status s = range_error;
if (L)//如果链表存在
{
     
if ((pos-1) >= 0 && (pos-1) < L->length)//从0开始 在范围内
{
     
*elem = L->elem[pos-1];//* 表示取值 取出放入
s = success;//修改状态
}
}
else
s = fatal;
return s;
}

3.2.4 表中按照值查找位置

Status List_Locate(SqListPtr L, ElemType elem, int *pos)
{
     
Status s = range_error;
if (L){
     
for (int i = 0; i < L->length; ++i){
     
if (L->elem[i] == elem){
     
*pos = i+1;
s = success;
break;
}
}
}
else s = fatal;
retu

3.2.5 在指定位置插入元素

Status List_Insert(SqListPtr L, int pos, ElemType elem)
{
     
Status s = range_error;
if ((pos-1) >= 0 && (pos-1) <= L->length)//在顺序表范围内
{
     
//顺序表存在并且还存在未使用的空间方便后移
if (L && L->length <L-> list_size )
{
     
//循环遍历后移 记得-1
for (int i = L->length-1; i >= pos-1; --i){
     
L->elem[i+1] = L->elem[i];
}
//插入
L->elem[pos-1 ] = elem;
//实际长度增加1
L->length++;
s = success;
}
}
else s = fail;
return 

3.2.6 删除指定位置的元素

Status List_delete(SqListPtr L, int pos)
{
     
Status s = range_error;
if ((pos-1) >= 0 && (pos-1) < L->length){
     
if(L && L->length > 0){
     
for (int i = pos ; i < L->length; ++i){
     
L->elem[i-1] = L->elem[i ];
L->length--;
s=success;
}
}
}
else s = fail;
return s;
}

3.3 顺序存储结构存在的问题

  1. 不能知道预先分配多少空间合适,尽管当空间不够可以分配更大的空间但是数据的前移造成时间浪费
  2. 插入和删除开销很大,循环遍历。

4 线性表的链式存储结构(全)

4.1 线性表的链式存储的基本概念

线性表-顺序表和链式表概念及其代码实现【数据结构与算法】_第3张图片

线性表-顺序表和链式表概念及其代码实现【数据结构与算法】_第4张图片

线性表-顺序表和链式表概念及其代码实现【数据结构与算法】_第5张图片
线性表-顺序表和链式表概念及其代码实现【数据结构与算法】_第6张图片
带头结点和不带头结点的区别
线性表-顺序表和链式表概念及其代码实现【数据结构与算法】_第7张图片

4.2 链式存储的C代码实现

4.2.1 链式存储的类型定义

typedef struct Node
{
     
ElemType elem;
struct Node *next;
}Node,*Ptr;
typedef Ptr *SqListPtr;

4.2.2 变量的定义和实现

Node n1, n2;
/* 定义2个结点变量*/
Ptr p = &n1;
/* 定义一个指向结点的指针变量p, 并存放n1的地址
(指针) */
n1.next=&n2; /* 结点n1的指针域存放结点n2的地址
*/
SqListPtr L=p; //定义一个单链表L
N2.next=NULL;

4.2.3 单链表按位置查找值

Status List_Retrieve(SqListPtr L, int pos, ElemType *elem)
{
     
//SqListPtr L是一个二重指针 
Status s = range_error;
Ptr p = (*L)->next;; /* 带头结点,移动p指向第一个元素结点*/
int i = 1;/*计数器*/
while (p && i < pos)){
      /* p指向的结点存在,且未到达指定位置*//*条件1防止pos>表长;条件2
控制取第pos个, 防pos<1 */
{
     
i++;
p = p->next;
}
if (p && i == pos)) /*找到指定位置,且该结点存在 防止i=0 -1 这种情况*/
{
     
*elem = p->data;
s = success;
}
return s;
}

4.2.4 单链表按值查找位置

Status List_Locate(SqListPtr L, ElemType elem, int *pos)
{
     
Status s = range_error;
Ptr p = (*L)->next;
int i = 1;
while (p != NULL){
     
if (p->elem == elem)break;
i++;
p = p->next;
}
if (p){
     
*pos = i;
s = success;
}
return s;
}

4.2.5 单链表上的插入操作

线性表-顺序表和链式表概念及其代码实现【数据结构与算法】_第8张图片
步骤(易错)

  • 找到ai-1的位置
  • 构造一个数据域为elem的新结点
  • 将ai-1 ->next 先挂到新节点上(elem->next=ai-1 ->next)
  • 再将ai-1->next=elem(不可换)
Status List_Insert(SqListPtr L, int pos-1, ElemType elem)
{
     
Status status ;
Ptr p,s;
status = List_Retrival (L, pos-1, &p);//判断是否存在这个位置 有没有越界
if (status == success){
     
s = (LinkedPtr)malloc(sizeof(Node));//创建新节点
if (s){
     
s->elem = 数据;//新结点挂上数据
s->next = p->next;//新节点next挂上ai
p->next = s;//ai-1挂上next
status = success;
}
else status = fatal;
}
else status = range_error;
return status;
}

4.2.6 单链表上的删除操作

线性表-顺序表和链式表概念及其代码实现【数据结构与算法】_第9张图片
步骤

  • 首先求得第i-1个结点的指针p
  • 修改第i-1个结点的后继域为第i+1个结点的地址
  • 再释放第pos个结点所占的存储空间
//不完整 要先用查找 找到对应位置(s p)的指针 
//再用如下函数进行删除
Status List_delete(SqListPtr L, int pos)
{
     
Status status=fail;
Ptr s, p;
status = List_Retrival (L, pos - 1, &p);
if (status == success)
{
     
s = p->next;
p->next = s->next;
free(s);
s = NULL;
status = success;
}
return status;
}

4.2.7 单链表的创建及插入n个数据

首先明确插入都是前插,操作都在空节点和第一个节点之间。如果要求a1 到 a n 顺序插入,那么实际上我们操作顺序是an 到 a1,看下图理解
线性表-顺序表和链式表概念及其代码实现【数据结构与算法】_第10张图片

Status List_Create(SqListPtr L, ElemType data[], int len){
     
Status s;
Ptr p;
s = List_Init(L);
if (s == success){
     
for (int i = len-1; i>=0; --i)//len个数据
{
     
p = (Ptr)malloc(sizeof(Node));//循环初始化len个节点
if (p)
{
     
p->elem = data[i];//数据放入新结点
//先填充新节点的next ,否则数据覆盖就不存在,顺序不能换
p->next = (*L)->next;
(*L)->next = p;//新结点挂载空节点的next上
}
else{
     
s = fail;
break;
}
}
}
return s

总结

对于数据结构与算法课程的重新学习整理,如有错误欢迎指出。

在这里插入图片描述

你可能感兴趣的:(数据结构与算法,数据结构,c++,c#,代码实现)