1 / 76

第 2 章 线 性 表

第 2 章 线 性 表. 2 . 1 线性表的定义和运算 2.2 线性表的顺序存储结构 2.3 链表 2.4 一元多项式的表示及相加. 2.1 线性表的定义和运算. 2.1.1 线性表的定义 2.1.2 线性表的运算. Return. 2.1.1 线性表的定义. 线性表: 是 n 个类型相同的数据元素的有限序列,数据元素之间是一对一的关系,即每个数据元素最多有一个直接前驱和一个直接后继 。. 例 1 英文字母表( A , B , C , … , Z) 是一个线性表 例 2. 数据元素. 线性表的定义.

adsila
Download Presentation

第 2 章 线 性 表

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第 2 章 线 性 表 • 2.1 线性表的定义和运算 • 2.2 线性表的顺序存储结构 • 2.3 链表 • 2.4 一元多项式的表示及相加

  2. 2.1 线性表的定义和运算 2.1.1 线性表的定义 2.1.2 线性表的运算 Return

  3. 2.1.1 线性表的定义 线性表:是n个类型相同的数据元素的有限序列,数据元素之间是一对一的关系,即每个数据元素最多有一个直接前驱和一个直接后继 。

  4. 例1 英文字母表(A,B,C,…,Z)是一个线性表 例2 数据元素

  5. 线性表的定义 线性表是由n (n≥0)个类型相同的数据元素a1,a2,…,an组成的有限序列,记做L=(a1,a2,…,ai-1,ai,ai+1, …,an)。 线性表的特点 同一性:线性表由同类数据元素组成,每一个ai必须属于同一数据对象。 有穷性:线性表由有限个数据元素组成,表长度就是表中数据元素的个数(即n)。n=0时称为空表,记作L=()。 有序性:线性表中表中相邻数据元素之间存在着序偶关系<ai,ai+1>。

  6. 2.1.2线性表的运算 基本运算: (1)initial_list(L) 操作前提:L为未初始化线性表。 操作结果:将L初始化为空表。 (2)list_length(L) 操作前提:线性表L已存在。 操作结果:如果L为空表则返回0,否则返回表中的元素个数。

  7. (3)get_element(L,i,&x) 操作前提:表L存在,且i值合法,即1≤i≤list_length(L)) 操作结果:用变量x返回线性表L中第i个元素的值。 (4)list_locate(L,x) 操作前提: 表L已存在,x为合法元素值。 操作结果: 如果L中存在元素x,则返回元素x所在位置,否则返回一个不存在的地址或标记。

  8. (5)list_insert (L,i,x) 操作前提:表L已存在,x为合法元素值且1≤i≤list_length(L)+1。 操作结果:在L中第i个位置之前插入新的数据元素x,L的长度加1。 (6)list_delete(L,i) 操作前提:表L已存在且非空, 1≤i≤list_length(L)。 操作结果:删除L的第i个数据元素,L的长度减1。

  9. 2.2 线性表的顺序表存储结构 2.2.1 顺序存储结构 2.2.2 顺序表基本运算的实现 Return

  10. 2.2.1 顺序存储结构 线性表的顺序存储结构(顺序映像): 用一组地址连续的存储单元依次存储线性表的数据元素。 顺序表: 采用顺序存储结构的线性表通常称为顺序表

  11. 存储地址 内存 元素序号 a1 LOC(a1) 1 LOC(a1) +L a2 2 n LOC(a1) +(n-1)L an 备用空间 • 元素地址计算方法: • LOC(ai)=LOC(a1)+(i-1)*L • LOC(ai+1)=LOC(ai)+L • 其中: • L—一个元素占用的存储单元个数 • LOC(ai)—线性表第i个元素的地址 • 特点: • 实现逻辑上相邻—物理地址相邻 • 实现随机存取

  12. 顺序存储结构的实现 可以借助于高级程序设计语言中的数组来表示,一维数组的下标与元素在线性表中的序号相对应。

  13. 以C语言为例 : 如何定义 顺序表? // 线性表的顺序存储结构 #define maxlen 100 //存储空间的初始分配量 typedef struct { elementtype data[maxlen]; //定义顺序表中元素的数组 int listlen; //定义表长度 }seqlist; seqlist *L; seqlist L; L.listlen; L.data[0] L->listlen; L->data[0]

  14. 2.2.2 顺序表运算的实现 • 表初始化 • 求表长度 • 按序号求元素 • 查找元素 • 插入元素 • 删除元素

  15. 表初始化initial_list(L) void initial_list(seqlist *L) {L->listlen=0;}

  16. 求表长度list_length(L) int list_length(seqlist L) {return L.listlen;}

  17. 按序号求元素get_element(L,i,elementtype &x) void get_element(seqlist L,int i,elementtype &x) { if (i<1||i>L.listlen) error("超出范围"); else x=L.data[i-1] }

  18. 查找运算list_locate(L,x) int list_locate(seqlist L,elementtype x) {//返回元素x在顺序表L中的序号 int i; for( i=0 ; i<L.listlen ; i++) if (L.data[i]==x) return i+1; return 0; }

  19. 插入运算list_insert(L,i,x) 定义: 在第i(1i  n+1)个元素前插入一个新的数据元素x,使长度为n的线性表 (a1,a2,……,ai-1,ai,……,an) 变成长度为n+1的线性表 (a1,a2,……,ai-1,x,ai,……,an) 算法分析:

  20. 数组下标 数组下标 内存 元素序号 元素序号 内存 0 0 a1 a1 1 1 a2 2 2 a2 1 1 插入x i-1 i-1 ai i i ai i i ai+1 i+1 i+1 ai+1 n n an an-1 n-1 n-1 n+1 n+1 n n an x

  21. 算法实现: void list_insert (seqlist L,int i,elementtype x){ int j; if(i<1||i>L.listlen+1) error("position error"); if(L.listlen>=maxlen) error ("overflow");} for(j=L.listlen-1;j>=i-1;j--) L.data[j+1]=L.data[j]; //插入位置之后元素后移 L.data[i-1 ]=x; ++L.listlen; }

  22. 算法时间复杂度T(n) 设Pi是在第i个元素之前插入一个元素的概率,则在长度为n的线性表中插入一个元素时,所需移动的元素次数的期望值(平均次数)为:

  23. 顺序表的删除运算list_delete(L,i) • 定义: 线性表的删除是指将第i(1i  n)个元素删除,使长度为n的线性表 (a1,a2,……,ai-1,ai,ai+1,……,an) 变成长度为n-1的线性表 (a1,a2,……,ai-1, ai+1, ……,an) • 算法分析: 需将第i+1至第n共(n-i)个元素前移

  24. 数组下标 内存 元素序号 数组下标 内存 元素序号 0 a1 1 a1 0 1 a2 2 a2 2 1 1 ai-1 ai-1 i-2 i-1 i-2 i-1 删除ai i-1 ai i i-1 ai+1 i i ai+1 i+1 i ai+2 i+1 an n-1 n-2 n an n-1 n-1 n n+1 n

  25. 算法实现: void list_delete(seqlist L,int i){ int k; if(i<1||i>L.listlen) error("删除位置错"); for(k=i;k<=L.listlen-1;++k) L.elem[k-1]=L.elem[k]; // 被删除元素之后的元素左移 - -L.listlen; // 表长减1 }

  26. 算法时间复杂度 设Qi是删除第i个元素的概率,则在长度为n的线性表中删除一个元素所需移动的元素次数的(期望值)平均次数为:

  27. 算法评价: • 在顺序表中插入或删除一个元素时,平均移动表的一半元素,当n很大时,效率很低。

  28. 例:顺序表的合并.有两个顺序表LA和LB,其元素均为非递减有序排列,编写一个算法,将它们合并成一个顺序表LC,要求LC也是非递减有序排列。例如LA=(2, 2, 3), LB=(1, 3, 3, 4), 则LC=(1, 2, 2, 3, 3, 3, 4)。 算法分析:设表LC是一个空表,为使LC也是非递减有序排列,可设两个指针i、j分别指向表LA和LB中的元素,若LA.data[i]>LB.data[j],则当前先将LB.data[j]插入到表LC中,若LA.data[i]≤LB.data[j] ,当前先将LA.data[i]插入到表LC中,如此进行下去,直到其中一个表被扫描完毕,然后再将未扫描完的表中剩余的所有元素放到表LC中。

  29. 例如LA=(2, 2, 3), LB=(1, 3, 3, 4), 则LC=(1, 2, 2, 3, 3, 3, 4)。 LA i LB j j 1 2 2 3 3 3 4 LC k k

  30. 算法实现: void   merge(seqlist &LA,  seqlist &LB,  seqlist &LC)   {  i=0;j=0;k=0;    while(i<=LA.listlen-1&&j<=LB.listlen-1)      if(LA.data[i]<=LB.data[j]) {         LC.data[k]= LA.data[i];    i++; k++;  }          else         { LC.data[k]=LB.data[j];    j++; k++;     }      while(i<=LA->listlen-1)      /*当表LA有剩余元素时,则将表LA余下的元素赋给表LC*/      {   LC.data[k]= LA.data[i];  i++; k++;     }      while(j<=LB.listlen-1)  /*当表LB有剩余元素时,则将表LB余下的元素赋给表LC*/       {   LC.data[k]= LB.data[j];    j++;  k++;    }         LC.listlen=LA.listlen+LB.listlen;    }

  31. 顺序存储结构的优缺点: 优点 逻辑相邻,物理相邻 可随机存取任一元素 缺点 插入、删除操作需要移动大量的元素

  32. 第 2 章 线 性 表 • 2.1 线性表的定义和运算 • 2.2 线性表的顺序存储结构 • 2.3 链表 • 2.4 一元多项式的表示及相加

  33. 结点 数据域 指针域 2.3 链表 Return 特点: • 用一组任意的存储单元存储线性表的数据元素 • 利用指针实现了用不相邻的存储单元存放逻辑上相邻的元素 • 每个数据元素ai,除存储本身信息外,还需存储其直接后继的信息 • 结点 • 数据域:元素本身信息 • 指针域:指示直接后继的存储位置

  34. H 存储地址 数据域 指针域 LI ZHAO SUN QIAN 1 LI 7 QIAN 13 WANG ZHOU ZHENG WU ^ SUN 19 H WANG 25 31 WU 31 ZHAO 37 ZHENG 43 ZHOU 例 线性表 (ZHAO,QIAN,SUN,LI,ZHOU,WU,ZHENG,WANG) 43 头指针 13 1 NULL 37 7 19 25

  35. next data p 结点(*p) 2.3.1 线性链表 定义:结点中只含一个指针域的链表叫线性链表,也叫单链表 typedef struct node{ elementtypedata; struct node *next; }node,*LinkList; 实现 node letter[8]; 用数组来存储元素的值和地址。 数据元素的个数固定不变,为 静态链表。 node *L,*p; (*p)表示p所指向的结点 (*p).datap->data表示p指向结点的数据域 (*p).nextp->next表示p指向结点的指针域 动态链表 生成一个node型新结点: p=(node *)malloc(sizeof(node)); 系统回收p结点:free(p)

  36. 头结点:在单链表第一个结点前附设一个结点叫头结点.头结点指针域为空表示线性表为空头结点:在单链表第一个结点前附设一个结点叫头结点.头结点指针域为空表示线性表为空 头结点 p …... L an ^ a1 a2 L ^ 空表 第一个数据元素的值:L->next->data 第二个数据元素的指针:L->next->next p->data p->next p->next->data p->next->next

  37. 单链表的基本运算 1.初始化单链表 2.求链表长度 3.按序号取元素 4.查找 5.插入 6.删除 7.头插法建立单链表 8.尾插法建立单链表

  38. L 1.初始化单链表 ^ //产生带头结点的单链表 void initial_list(node *&L) { L =(node *)malloc(sizeof(node)); L->next=NULL; }

  39. p 头结点 L …... an ^ a1 a2 2.求链表长度 int list_length(node *L) { int n=0; node *p=L->next; while(p!=NULL) { n++; p=p->next; } return n; }

  40. p 头结点 L …... an ^ a1 a2 3.按序号取元素 node *get_element(node *L , int i) { node *p=L->next; int j=1; while( j!=i && p!=NULL) { p=p->next; j++; } return p; }

  41. 4.查找

  42. p a b e n 算法演示 L node *list_locate(node *L;elementtype e) { node *p=L->next; while(p!=Null && p->data!=e) { p=p->next; } return p; } …… …… ^

  43. b p a x s 5.插入 插入:在线性表两个数据元素a和b间插入x,已知p指向a p->next=s; s->next=p->next; 算法评价

  44. 算法实现 void list_insert(node *L, int i, elementtyp x){ //在带头结点的单链表L中第i个位置之前插入元素x node *s, p=*L ; int j=0; while(p&&j<i-1){p=p->next;++j;}//寻找第i-1个结点 if (!p | |j>i-1) error("序号错"); s=(node *)malloc(sizeof(node));//生成新结点 s->data=x; s->next=p->next; p->next=s; }

  45. p b a c q 6.删除 • 删除:单链表中删除b,设p指向a p->next=q->next; • 算法评价

  46. 算法实现 void list_delete(node *L, int i) {//在带头结点的单链表L中删除第i个元素 node *p=L,*q; int j=0; while (p->next && j<i-1) {p=p->next; ++j; } //寻找第i-1个结点 if( !(p->next) || j>i-1) error("删除序号错"); q=p->next; p->next=q->next; free (q); }

  47. p L a b p 7.头插法建立单链表 算法描述: 逆位序输入n个元素的值,建立带头结点的单链表 算法演示:如输入二个元素a,b,头插法建立单链表 ^ ^

  48. 头插法建立单链表算法实现 void createlist_H(node * &L) { node *p; elementtype x; L=(node *)malloc(sizeof(node)); L->next=NULL;//先建立一个带头结点的单链表 cin >>x ; //输入第一个元素的值 while ( x!=End_of_Num) //x不是结束符时 {p=(node *)malloc(sizeof(node)); //生成新结点 p->data=x; p->next=L->next; L->next=p; //插入到表头 cin >> x ; //输入下一个元素的值} }

  49. r r L p 8.尾插法建立单链表 算法描述: 正位序输入n个元素的值,建立带头结点的单链表 算法演示:如输入二个元素a,b,尾插法建立单链表 ^ b a ^

  50. 尾插法建立单链表算法实现: void createlist_R( node * &L) { node *r,*p; elementtype x ; L=(node *)malloc(sizeof(node)); L->next=NULL; //先建立一个带头结点的单链表 r=L; //r为表尾元素指针 cin>> x; while( x!=End_of_Num) { p=(node *)malloc(sizeof(node)); //生成新结点 p->data=x; p->next=NULL; r->next=p; r=p; //插入到表尾 cin>>x; }}

More Related