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
2007-9-23 运城学院计科系《数据结构》 1
《数据结构》第二章 线性表
运城学院计算机科学与技术系
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 、存储结构:顺序存储 ( 顺序表 ) 链式存储 ( 链表 )
初始化 求表长 访问元素 查找 删除元素 插入元素
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
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
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 )
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 移动次数
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 )
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)
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 中
2007-9-23 运城学院计科系《数据结构》 10
2.3 链表之单链表
一、单链表定义结点:数据元素与指向后继的指针存储在一起称为结点数据域:结点中存放数据元素的部分指针域:结点中存放指针的部分单链表:结点中只有一个指针的链表
链表需要有个指向首结点或者头结点的指针来标识;
a1 a2 a3 an ^
head
a1 a2 a3 an ^L
头结点
2007-9-23 运城学院计科系《数据结构》 11
2.3 链表之单链表
单链表的数据类型定义:
typedef struct node{ datatype data; /* 数据域,存放数据元素 */ struct node *next; /* 指针域,指向后继元素 */ }listnode,Typedef listnode * linklist; /* 定义头指针类型 */
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)
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)
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)
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; }
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
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 ①②
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; }
2007-9-23 运城学院计科系《数据结构》 19
2.3 链表之循环链表和双向链表
循环链表:表尾结点的 next 指针指向表头结点的链表。
双向链表:结点存在两个指针域,一个指向后继结点,另一个指向前驱结点。
双向循环链表:
^
^
2007-9-23 运城学院计科系《数据结构》 20
2.3 链表之循环链表和双向链表
双向链表的数据类型定义:typedef struct dbnode{ elemtype data; struct dbnode *prior; struct dbnode *next; }DBNODE, *DBNODEPTR,*DBLINKLIST;
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
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
2007-9-23 运城学院计科系《数据结构》 23
2.4 链表与顺序表对比
随机访问 插入操作 删除操作 内存空间
顺序表YesO(1)
O(n) O(n) 受限
链表No
O(n)O(1) O(1) 不受限
2007-9-23 运城学院计科系《数据结构》 24
O V E RO V E R
《数据结构》第二章 线性表