第二章 线性表【数据结构与算法】1

本文涉及的产品
传统型负载均衡 CLB,每月750个小时 15LCU
EMR Serverless StarRocks,5000CU*H 48000GB*H
网络型负载均衡 NLB,每月750个小时 15LCU
简介: 第二章 线性表【数据结构与算法】1

配套资源下载

数据结构资源下载导航【数据结构】

第二章 线性表

2.1 应用实例

应用实例一 约瑟夫环问题(Josephus problem)

约瑟夫环问题是由古罗马的史学家约瑟夫提出的。问题描述为:编号为1,2.,n的n个人按顺时针方向围坐在一张圆桌周围,每人持有一个密码(正整数)。一开始任选一个正整数作为报数上限值m,从第一个人开始按顺时针方向自1开始报数,报到m时停止报数,报m的那个人出列,将其密码作为新的m值,并从其顺时针方向的下一个人开始重新从1报数,数到m的那个人又出列;如此下去,直至圆桌周围的人全部出列为止。这个游戏的实现只需将每个人的信息什 为一个结点,结点中存放每个人的编号和密码。由于要反复做删除操作,所以采用单向循环链表实现比较方便,详见本章2.6节。

应用实例二 一元多项式运算器

要实现一元多项式运算器,首先要设计表示一元多项式P=p0+p1x+p2x^2+…+pn x^n"的合适的 数据结构,并支持多项式的下列运算。

  • 建立多项式。
  • 输出多项式。
  • +,两个多项式相加,建立并输出和多项式。
  • -,两个多项式相减,建立并输出差多项式。
  • *,多项式乘法。
  • (),求多项式的值。
  • derivative(),求多项式导数。

这个问题看起来很复张,但只要用本章将要学习的带头结点的单链表来存储多项式,头结点中存放多项式的参数(如项数等),问题就可以迎刃而解。详细的实现分析及算法见本章2.6节。

2.2 线性表的概念及运算

2.2.1线性表的逻辑结构

线性表是n(n>=0)个数据元素的有限序列。在表中,元素存在线性的逻辑关系:表中有且仅有一个开始结点;有且仅有一个终端结点;除开始结点外,表中的每个结点均只有一个前驱结点(predecessor);除终端结点外,表中的每个结点均只有一个后继结点(successor)。根据它们之间的关系可以排成一个线性序列,记作(a1,a2,…,an)

2.2.2 线性表的运算

基本操作

① InitList(L)       线性表初始化,构造一个空的线性表L。
② ListLength(L)     求线性表的长度,返回线性表L中数据元素的个数 
③ GetElem(L,i,x)    用x返回线性表中的第i个数据元素的值。
④ locaionElem(L,x)    按值查找,确定数据元素x在表中的位置。  
⑤ ListInsert(L,i,x)   插入操作,在线性表L中第i个位置之前插入一个新元素。L的长度加1。
⑥ ListDelete(L,i)   删除操作,删除线性表L中的第i个元素,L的长度减1。  
⑦ ListEmpty(L)      判断线性表L是否为空,空表返回TRUE,非空表返回FALSE。  
⑧ ClearList(L)      将已知的线性表L置为空表。
⑨ DestroyList(L)      销毁线性表L。

其他操作:合并、分拆、复制、排序等等。

2.3 线性表的顺序存储

2.3.1 顺序表

顺序存储是指在内存中用一块地址连续的存储空间按顺序存储线性表的各个数据元素。采用顺序存储结构 的线性表称为“顺序表”顺序表中逻辑上相邻的数据元素在物理存储位置上也是相邻的。

#define MAXSIZE <线性表可能达到的最大长度>  
typedef int ElemType;
typedef struct
{   ElemType elem[MAXSIZE];
  int length;//线性表长度
} SeqList;

2.3.2 顺序表的基本运算

相关代码请看配套资源

1-顺序表.c

int main(){
  SeqList _L;
  SeqList *L=&_L;
  //初始化 
  Init(&_L);
  //创建 
  CreateList(L,4);
  Output(L);
  //插入 
  printf("在1处插入1\n"); 
  Insert(L,1,1);
  printf("在2处插入2\n"); 
  Insert(L,2,2);
  printf("插入之后"); 
  Output(L);
  printf("表长:%d\n",ListLength(L));
  //删除
  printf("删除1\n"); 
  ElemType d=-1;
  Delete(L,1,&d);
  printf("删除之后"); 
  Output(L);
  //查询
  printf("查询1\n"); 
  ElemType x=1;
  int i=Location(L,x);
  printf("序号%d\n",i);
  printf("按索引i查询\n"); 
  ElemType y;
  GetElem(L,i,&y);
  printf("值%d",y); 
} 

运行结果如下



[例 2-1] 两个顺序表合并

有两个顺序表LA和LB,其元素均为非递减有序排列, 编写一个算法,将它们合并成一个顺序表LC,要求LC也是非递减有序排列。
算法思路:依次扫描A和B的元素,比较当前元素的值,将较小值的元素赋给C,如此直到一个线性表扫描完毕,然后将未外理完的顺序表的余下部分元麦连在表C的后面即可。表C的容量要能够容纳A、B两个线性表中的所有元素。

[算法2-5] 两个顺序表合并

void merge(SeqList* A, SeqList* B,SeqList* C)
{ int i,j,k;
  i=1;j=1;k=1;
  while (i<=A->length && j<= B->length)
    if (A->elem[i]<=B->elem[j])
      C->elem[k++]=A->elem[i++];
    else C->elem[k++]=B->elem[j++];
  while (i<=A->length)
    C->elem[k++]=A->elem[i++];
  while (j<=B->length)
    C->elem[k++]=B->elem[j++];
  C->length=A->length+B->length;
}

算法的时间复杂度是0(m+n),其中m是A的表长,n是B的表长。

2.4 线性表的链式存储

链式存储,通过“链”建立起数据元素之间的逻辑关系,这种用链接方式存储的线性表简称链表(link list)。

2.4.1 单链表

链表中的每一个结点都至少包括两个与,一个域存储数据元素信息,称为“数据域”;另一个域存储之间后继元素的地址,称为“指针域”。

结点定义如下:

typedef struct code 
{ DataType data;//数据域
  struct node * next;//指针域
}LNode,*LinkList;

n个元素的线性表通过每个结点的指针域连 接成了一条“链子”,故形象地称之为“链表”。因为每个结点中只有一个指向其直接后继的指针所以称其为单链表

2.4.2 单链表基本运算

相关代码请看配套资源

2-单链表.c

void main(){
  //建立 
  LinkList h=CreatByBear();
  OutPut(h);
  //插入 
  printf("在1处插入1\n"); 
  Insert(h,1,1);
  printf("在2处插入2\n"); 
  Insert(h,2,2); 
  printf("插入之后\n"); 
  OutPut(h);
  //删除 
  printf("删除2\n"); 
  Delete(h,2);
  printf("删除之后\n"); 
  OutPut(h);
  //按序号查询 
  LNode *p;
  p=Get(h,1);
  printf("按序号查找到的信息如下:\n");
  printf("%d\n",p->data);
  //按值查询
  LNode *s;
  s=Locate(h,1);
  printf("按值查找到的信息如下:\n");
  printf("%d\n",s->data);
} 

运行结果如下



[例]

有两个单链表LA和LB,其元素均为非递减有序排列, 编写一个算法,将它们合并成一个单链表LC,要求LC也是非递减有序排列。

要求:新表LC利用原表的存储空间。

[解]

LinkList MergeLinkList(LinkList LA,LinkList LB)
{
  LNode *pa,*pb;
  LinkList LC;
  pa=LA->next;
  pb=LB->next
  LC=LA;
  LC->next=NULL;
  r=LC;
  while(pa&&pb)
  {  
    if(pa->data<=pb->data)
    { 
      r->next=pa;
      r=pa;
      pa=pa->next;  
    }
    else
    {  
      r->next=pb;
      r=pb;
      pb=pb->next; 
    }
  if(pa) r->next=pa;
  else  r->next=pb;
  free(LB);
  return(LC);
}
相关实践学习
SLB负载均衡实践
本场景通过使用阿里云负载均衡 SLB 以及对负载均衡 SLB 后端服务器 ECS 的权重进行修改,快速解决服务器响应速度慢的问题
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
相关文章
|
6月前
|
存储 算法 数据安全/隐私保护
第二章 线性表【数据结构与算法】【精致版】
第二章 线性表【数据结构与算法】【精致版】
125 0
|
算法
数据结构与算法2.1线性表、链表
数据结构与算法2.1线性表、链表
37 0
数据结构与算法2.1线性表、链表
|
22天前
|
算法 安全 搜索推荐
2024重生之回溯数据结构与算法系列学习之王道第2.3章节之线性表精题汇总二(5)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
IKU达人之数据结构与算法系列学习×单双链表精题详解、数据结构、C++、排序算法、java 、动态规划 你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
5月前
|
算法
数据结构和算法学习记录——线性表之双向链表(上)-结点类型定义、初始化函数、创建新结点函数、尾插函数、打印函数、尾删函数
数据结构和算法学习记录——线性表之双向链表(上)-结点类型定义、初始化函数、创建新结点函数、尾插函数、打印函数、尾删函数
48 0
|
5月前
|
存储 算法
数据结构和算法学习记录——特殊线性表之队列-队列的概念、队列结构体类型定义 、基本接口函数、初始化函数、销毁队列函数、入队列函数、判断队列是否为空、出队列函数、读取队头队尾的数据 、计算队列数据个数
数据结构和算法学习记录——特殊线性表之队列-队列的概念、队列结构体类型定义 、基本接口函数、初始化函数、销毁队列函数、入队列函数、判断队列是否为空、出队列函数、读取队头队尾的数据 、计算队列数据个数
42 0
|
5月前
|
算法 C语言
数据结构和算法学习记录——特殊线性表之栈(下)-销毁栈函数、判断栈是否为空、压栈函数、出栈函数、取栈顶元素、计算栈中有多少个元素、栈有关习题-有效的括号
数据结构和算法学习记录——特殊线性表之栈(下)-销毁栈函数、判断栈是否为空、压栈函数、出栈函数、取栈顶元素、计算栈中有多少个元素、栈有关习题-有效的括号
36 0
|
5月前
|
算法
数据结构和算法学习记录——特殊线性表之栈(上)-栈的概念、栈的结构、链式栈数组栈、栈的结构体定义、栈的基本接口函数、栈顶初始化函数
数据结构和算法学习记录——特殊线性表之栈(上)-栈的概念、栈的结构、链式栈数组栈、栈的结构体定义、栈的基本接口函数、栈顶初始化函数
33 0
|
5月前
|
算法
数据结构和算法学习记录——线性表之双向链表(下)-头插函数、头删函数、查找函数、pos位置之前插入结点、pos位置删除结点及其复用、销毁链表函数
数据结构和算法学习记录——线性表之双向链表(下)-头插函数、头删函数、查找函数、pos位置之前插入结点、pos位置删除结点及其复用、销毁链表函数
30 0
|
5月前
|
算法
数据结构和算法学习记录——线性表之单链表(下)-头插函数、尾删函数、头删函数、查找函数、pos位置插入&删除数据、单链表销毁
数据结构和算法学习记录——线性表之单链表(下)-头插函数、尾删函数、头删函数、查找函数、pos位置插入&删除数据、单链表销毁
62 0
|
5月前
|
存储 算法
数据结构和算法学习记录——线性表之单链表(上)-初始单链表及其尾插函数(顺序表缺陷、单链表优点、链表打印)
数据结构和算法学习记录——线性表之单链表(上)-初始单链表及其尾插函数(顺序表缺陷、单链表优点、链表打印)
39 0
下一篇
无影云桌面