24
2007-9-23 运运运运运运运 运运运运运 《》 1 运运运运运 《》 运运运 运运运 运运运运 运运运运运运运运运

《 数据结构 》 第二章 线性表

  • Upload
    kalyca

  • View
    121

  • Download
    0

Embed Size (px)

DESCRIPTION

《 数据结构 》 第二章 线性表. 运城学院 计算机科学与技术系. 2.1 线性表的逻辑结构. 1 、线性表定义: n ( n≧0 )个结点的有穷序列。即:          a 1 、 a 2 、 a 3 … a i 、 a i+1 … a n    其中: a i 代表一个结点, i 为 a i 在线性表中的位置序号, n 为表长。或者: B=(A,R), A={a i |i=1,2,..,n},R={|I=2,3, … ,n} 特点:一个始点 a 1 一个终点 a n 线性表的逻辑结构为线性结构 - PowerPoint PPT Presentation

Citation preview

Page 1: 《 数据结构 》 第二章  线性表

2007-9-23 运城学院计科系《数据结构》 1

《数据结构》第二章 线性表

运城学院计算机科学与技术系

Page 2: 《 数据结构 》 第二章  线性表

2007-9-23 运城学院计科系《数据结构》 2

2.1 线性表的逻辑结构1 、线性表定义: n ( n 0≧ )个结点的有穷序列。即:   

                a1 、 a2 、 a3…ai 、 ai+1…an     其中: ai 代表一个结点, i 为 ai 在线性表中的位置序号,

n 为表长。或者: B=(A,R), A={ai|i=1,2,..,n},R={<ai-1,ai>|I=2,3,…,n}

特点:一个始点 a1      

    一个终点 an    线性表的逻辑结构为线性结构

    1 - 1 的关系 2 、常见的操作:

3 、存储结构:顺序存储 ( 顺序表 ) 链式存储 ( 链表 )

初始化 求表长 访问元素  查找  删除元素 插入元素

Page 3: 《 数据结构 》 第二章  线性表

2007-9-23 运城学院计科系《数据结构》 3

2.2 顺序存储结构一、顺序表:线性表的顺序存储。存储分配:一块连续的存储空间 ---- 存放元素     一个整形单元 ---- 记表中的元素个数

顺序表的 语言描述:typedef struct node {datatype data[listsize];  int length;  }seqlist; seqlist l; l------ 顺序表特点:随机存取 ---loc(ai)=loc(a1)+(i-1)*c 存取密度高 --- 物理上的相邻体现逻辑上的 相邻

数据元素的逻辑顺序与在内存中的存储顺序完全一致,不需要额外存储数据元素之间的关系

a1a2a3

an

l.data

l.length

Page 4: 《 数据结构 》 第二章  线性表

2007-9-23 运城学院计科系《数据结构》 4

2.2 顺序存储结构访问形式 :

结构体变量形式 指针变量形式l.data[i] 访问第 i 个结点 l->data[i]

l.length 表长 l->length l.data[l.length] 访问最后元素 l->data[l->length]

a1a2a3

an

l.data

l->data

l.length

l->length

Page 5: 《 数据结构 》 第二章  线性表

2007-9-23 运城学院计科系《数据结构》 5

2.2 顺序存储结构2 、基本操作在顺序表上的实现1) 、插入 insertlist(l,i,x)

时间复杂度: O(n)

void insertlist(seqlist*l,int i,datatype x)

{if(i<1||i>l->length+1) error(“position error”);

if(l->length=listsize) error(“overflow”);

for(j=l->length-1;j>=i-1;j--)

  l->data[j+1]=l->data[j];

l->data[i-1]=x;

l->length++;

}注意:指针作为函数参数的特点,在此算法中结构体变量不能作为函数参数。

判断 i位置的合法性

元素移动 n-i+1次

插入并修改表长

基本思想:是指在表的第 i 个( 1 i n+1≦≦ )的位置上,插入一个新结点 x ,使长度为 n 的线性表( a1,a2,…,ai-1,ai,…,an )

变成长度为 n+1 的线性表

( a1,a2,…,ai-1,x,a'i+1,…,a'n+1 )

Page 6: 《 数据结构 》 第二章  线性表

2007-9-23 运城学院计科系《数据结构》 6

插入 insertlist(l,i,x) 时间效率分析

基本操作 ------ 元素的移动因为元素的移动次数与位序有关,所以讨论平均移动次数。

平均移动次数 =

其中 Pi=1/(n+1) 为每个位置插入的概率在第 i 位插入元素移动的次数为: n-i+1

所以 Eis=T(n)==n/2

时间复杂性为 O ( T(n) ) =O(n)

结论:插入时元素的移动次数是表长的一半,效率较低。

1

1

*n

i

pi 移动次数

Page 7: 《 数据结构 》 第二章  线性表

2007-9-23 运城学院计科系《数据结构》 7

2 、基本操作在顺序表上的实现

2 、基本操作在顺序表上的实现

2 )、删除第 i 个元素 时间复杂度: O(n)

void deletelist(seqlist*l,int i) {if(i<1||i>l->length) error(“position error”);

for(j=i;j<=l->length-1;j++) l->data[j-1]=l->data[j]; l->length--; } 注意:在此算法中结构体变量不能作为函数参数。同理分析: Eds=(n-1)/2 时间复杂性为 O ( T(n) ) =O(n)结论:插、删时元素的移动次数为 O(n) ,效率较低。

几乎表长的一半

基本思想:删除表中第 i 个( 1 i n≦≦ )位置上的元素,使长度为 n 的线性表

( a1,a2,…,ai-1,ai,ai+1…,an )变成长度为 n-1 的线性表

( a1,a2,…,ai-1,a'i,…,a'n-1 )

Page 8: 《 数据结构 》 第二章  线性表

2007-9-23 运城学院计科系《数据结构》 8

2.2 顺序存储结构2 、基本操作在顺序表上的实现 void creatsqlist(SEQLIST *L)

{ int i; printf(" 请输入元素个数 \n"); scanf("%d",&L->len); printf(" 请输入 %d 个元素 \n"); for(i=0;i<L->len;i++) scanf("%d",&L->data[i].key); /* 略去了其他数据项的输入 */ }

1 、线性表的创建 时间复杂度: O(n)

Page 9: 《 数据结构 》 第二章  线性表

2007-9-23 运城学院计科系《数据结构》 9

2 、顺序表顺序表的操作实例【例】线性表的合并 时间复杂度: O(n+m)

void Sqmerge(SQLIST La,SQLIST Lb, SQLIST *Lc){ int i=0,j=0,k=0,m,n; n=La.len;m=Lb.len;Lc->len=m+n; while(i<n&&j<m) if(La.elem[i].key<=Lb.elem[j].key) Lc->elem[k++]=La.elem[i++]; else Lc->elem[k++]=Lb.elem[j++]; while(i<n)Lc->elem[k++]=La.elem[i++]; while(j<m)Lc->elem[k++]=Lb.elem[j++]; }

将 La 或 Lb中的剩余部分续接到 Lc

依次将 La,Lb中的较小者

续接到 Lc 中

Page 10: 《 数据结构 》 第二章  线性表

2007-9-23 运城学院计科系《数据结构》 10

2.3 链表之单链表

一、单链表定义结点:数据元素与指向后继的指针存储在一起称为结点数据域:结点中存放数据元素的部分指针域:结点中存放指针的部分单链表:结点中只有一个指针的链表

链表需要有个指向首结点或者头结点的指针来标识;

a1 a2 a3 an ^

head

a1 a2 a3 an ^L

头结点

Page 11: 《 数据结构 》 第二章  线性表

2007-9-23 运城学院计科系《数据结构》 11

2.3 链表之单链表

单链表的数据类型定义:

typedef struct node{ datatype data; /* 数据域,存放数据元素 */ struct node *next; /* 指针域,指向后继元素 */ }listnode,Typedef listnode * linklist; /* 定义头指针类型 */

Page 12: 《 数据结构 》 第二章  线性表

2007-9-23 运城学院计科系《数据结构》 12

2.3 链表之单链表二、单链表的基本操作

LINKLIST creatlinklist(){ LINKLIST head; NODEPTR p,q;int i,n;elemtype e; L=(NODEPTR)malloc(LEN); L->next=NULL; q=L; scanf("%d",&n); for(i=1;i<=n;i++) { p=(NODEPTR)malloc(LEN); getelem(&e);p->data=e; q->next=p;q=p;}//for q->next=NULL; return L; }

1 、线性表的创建 时间复杂度: O(n)

Page 13: 《 数据结构 》 第二章  线性表

2007-9-23 运城学院计科系《数据结构》 13

2.3 链表之单链表单链表的基本操作

void travlist(LINKLIST L){/* L 带有头结点 */ NODEPTR p; p=L->next; /* 指向首结点 */ while(p) {/* 沿着 next 链依次访问结点 */ printf("%3d",p->data.key); p=p->next; } printf("\n"); }

2 、线性表的遍历 时间复杂度: O(n)

Page 14: 《 数据结构 》 第二章  线性表

2007-9-23 运城学院计科系《数据结构》 14

2.3 链表之单链表单链表的基本操作

NODEPTR getelemi(LINKLIST L,int i, NODEPTR *pre)/*L 带有头结点 */{NODEPTR p,q;int j; if(i<=0)return NULL; q=L; *pre=NULL; p=L->next;j=1;/* p 指向了第 j 个元素 */ while(p&&j<i) /* 只要 p 不空,向后数 */ { q=p;p=p->next;++j; /* 记下 p 的前驱 */ } if(p)*pre=q; return p; }

3 、定位第 i 个元素

时间复杂度: O(n)

Page 15: 《 数据结构 》 第二章  线性表

2007-9-23 运城学院计科系《数据结构》 15

2.3 链表之单链表单链表的基本操作4 、定位结点 p 的前驱

时间复杂度: O(n)

NODEPTR preelem(LINKLIST L, NODEPTR p){ NODEPTR q; q=L; while(q&&q->next!=p) q=q->next; return q; }

Page 16: 《 数据结构 》 第二章  线性表

2007-9-23 运城学院计科系《数据结构》 16

2.3 链表之单链表单链表的基本操作5 、删除第 i 个结点 时间复杂度: O(n)

int delelem(LINKLIST L,int i){ NODEPTR p,pre; p=getelem(L,i,&pre); if(p){pre->next=p->next;free(p);return 1;} else return 0; }

pre p

Page 17: 《 数据结构 》 第二章  线性表

2007-9-23 运城学院计科系《数据结构》 17

int inselem(LINKLIST L,int i, elemtype e, int mark)/*mark 表示在第 i 个结点的前或后*/ { NODEPTR p,s,pre; p=getelemi(L,I,&pre); if(p) { s=(NODEPTR)malloc(LEN); s->data=e; if(mark==1) {s->next=p->next;p->next=s;} else {s->next=p;pre->next=s;} return 1; } else return 0; }

2.3 链表之单链表单链表的基本操作6 、在第 i 个结点处插入

时间复杂度: O(n)

pre p

s ①②

pre p

s ①②

Page 18: 《 数据结构 》 第二章  线性表

2007-9-23 运城学院计科系《数据结构》 18

LINKLIST LkMerge(LINKLIST La, LINKLIST Lb)/*La,Lb 没有头结点 */{NODEPTR pa,pb,tail; LINKLIST head; pa=La;pb=Lb;/* 下面 if 语句定位新链表的首结点 */ if(pa->data.key<=pb->data.key) {head=tail=pa;pa=pa->next;} else {head=tail=pb;pb=pb->next;}

2.3 链表之单链表单链表的操作实例

线性表的合并 时间复杂度: O(n+m)

while(pa&&pb) if(pa->data.key<=pb->data.key) {tail->next=pa;tail=pa;pa=pa->next;} else {tail->next=pb;tail=pb;pb=pb->next;} tail->next=pa?pa:pb; /* 如果 pa,pb 哪个未空 , 直接续接到 tail 后面 */ return head; }

Page 19: 《 数据结构 》 第二章  线性表

2007-9-23 运城学院计科系《数据结构》 19

2.3 链表之循环链表和双向链表

循环链表:表尾结点的 next 指针指向表头结点的链表。

双向链表:结点存在两个指针域,一个指向后继结点,另一个指向前驱结点。

双向循环链表:

^

^

Page 20: 《 数据结构 》 第二章  线性表

2007-9-23 运城学院计科系《数据结构》 20

2.3 链表之循环链表和双向链表

双向链表的数据类型定义:typedef struct dbnode{ elemtype data; struct dbnode *prior; struct dbnode *next; }DBNODE, *DBNODEPTR,*DBLINKLIST;

Page 21: 《 数据结构 》 第二章  线性表

2007-9-23 运城学院计科系《数据结构》 21

2.3 链表之循环链表和双向链表双向循环链表的结点插入算法

int inselem(DBNODEPTR p,elemtype e){/* p 指向某双向循环链表中的某个结点 ,将 e 结点插入到 p 的后面 */ DBNODEPTR s,r; s=(DBNODEPTR)malloc(sizeof(DBNODE)); if(!s)return 0; s->data=e;/* 建立新的结点 */ r=p->next; s->next=r; r->prior=s; p->next=s; s->prior=p; }

p r

s

Page 22: 《 数据结构 》 第二章  线性表

2007-9-23 运城学院计科系《数据结构》 22

2.3 链表之循环链表和双向链表双向循环链表的结点删除算法

void delelem(DBNODEPTR p){/*p 指向某双向循环链表某结点,这个算法将其从链表中摘除 */ DBNODEPTR q,r; q=p->prior; r=p->next; q->next=r; r->prior=q; /* 也可以这样操作: p->prior->next=p->next; p->next->prior=p->prior; */ }

q p r

Page 23: 《 数据结构 》 第二章  线性表

2007-9-23 运城学院计科系《数据结构》 23

2.4 链表与顺序表对比

随机访问 插入操作 删除操作 内存空间

顺序表YesO(1)

O(n) O(n) 受限

链表No

O(n)O(1) O(1) 不受限

Page 24: 《 数据结构 》 第二章  线性表

2007-9-23 运城学院计科系《数据结构》 24

O V E RO V E R

《数据结构》第二章 线性表