第
Download
1 / 37

第 3 章 链式存储结构 - PowerPoint PPT Presentation


  • 124 Views
  • Uploaded on

第 3 章 链式存储结构. 第 3 章 链式存储结构. 3.1 线性表的链式存储结构 3.1.1 单链表上的基本运算 3.1.2 循环链表 3.1.3 双向链表 3.2 线性表的顺序和链式存储结构的比较 3.3 应用举例及分析 习题. 3.1 线性表的链式存储结构. 线性表的链式存储结构特点: 用一组 地址任意 的存储单元存放线性表中的数据元素。. 结点: 数据域 ( 数据元素的信息 ) + 指针域 ( 指示直接后继存储位置 ) = 结点 ( 表示数据元素或数据元素的映象 ). 链表: 以“结点的序列”表示线性表称作 链表。.

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about ' 第 3 章 链式存储结构' - howard-herrera


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.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript

3章 链式存储结构


3章 链式存储结构

3.1线性表的链式存储结构

3.1.1 单链表上的基本运算

3.1.2 循环链表

3.1.3 双向链表

3.2线性表的顺序和链式存储结构的比较

3.3应用举例及分析

习题


3.1线性表的链式存储结构

线性表的链式存储结构特点:用一组地址任意的存储单元存放线性表中的数据元素。

结点:

数据域(数据元素的信息)+指针域(指示直接后继存储位置)=结点(表示数据元素或数据元素的映象)

链表:以“结点的序列”表示线性表称作链表。


3.1线性表的链式存储结构

(a) 线性链表的图示; (b) 线性链表的一般表示

线性链表示意图


a1 a2 … ... an ^

线性表为空表时,

头结点的指针域为空

头指针

头指针

头指针

头结点

以线性表中第一个数据元素a1的存储地址作为线性表的地址,称作线性表的头指针。

有时为了操作方便,在第一个结点之前虚加一个“头结点”,以指向头结点的指针为链表的头指针。


单链表的数据结构

type struct node

{char data;

struct node *next

}LINKLIST;

结点的申请、释放:

若LINKLIST head,*new;则可用:

head=malloc (sizeof (LINKLIST));申请结点

free (head);释放结点



3 1 1
3.1.1单链表上的基本运算

一、建立单链表

假设线性表中结点的数据类型是字符,逐个输入这些字符型的结点,并以 ‘$’为输入结束标记。动态地建立单链表的常用方法有如下两种:

1、头插法建表

该方法从一个空表开始,重复读入数据,生成新结点,将读入数据存放到新结点的数据域中,然后将新结点插入到当前链表的表头上,直到读入结束标志为止。算法如下:


main( )

{

LINKLIST * head , * new ;

Char ch ;

while ( ( ch=getchar ()) !=’$’)

new=malloc ( sizeof ( LINKLIST)) ;

new->data=ch ;

new->next= head ;

head =new ;

}


2、尾插法建表

头插法建立链表虽然算法简单,但生成的链表中结点的次序和输入的顺序相反。若希望二者次序一致,可采用尾插法建表。该方法是将新结点插入到当前链表的表尾上,为此必须增加一个尾指针r,使其始终指向当前链表的尾结点。

算法如下:


main( )

{LINKLIST * head , * last , * new ;

Char ch ;

new=malloc ( sizeof (LINKLIST )) ;

head=new ; last=new ;

new->next=NULL ;

while ( ch=getchar (1) !=’$’)

{new=malloc ( sizeof ( LINKLIST)) ;

new->data=ch ;

last->next=new ;

last=new ;

new->next=NULL ;}


二、查找运算

1、按序号查找第i个结点

在有头指针的单链表中找第i个结点,算法 为:设head为头,p为当前结点,0为头结点序号,i为计数器,则可使p依次下 移找结点,并使i同时递增记录结点号,找到返回结点地址,找不到返回NULL。


算法如下:

LINKLIST *get ( int i , LINKLIST *head )

{int j=0 ;

LINKLIST *p=head ;

while (cj<i) &&(p->next !=NULL )

{p=p->next ; i++ ; }

if (i= =j )

return p ;

else

return NULL ;

}


2、按值查找

按值查找是在链表中,查找是否有结点值等于给定值x的结点,若有,则返回首次找到的其值为x的结点的存储位置;否则返回NULL。查找过程从开始结点出发,顺着链表逐个将结点的值和给定值x作比较。

其查找流程及算法如下:



按值查找算法:

LINKLIST * locate (Char x , LINKLIST * head )

{LINKLIST *p ;;

p=head->next ;

while ( p->data= = x )

return p ;

else

p=p->next ; }

return NULL ;

}


三、插入运算

插入运算是将值为x的新结点插入到表的第i个结点的位置上,即插入到ai-1与ai之间。因此,首先找到ai-1的存储位置p,然后生成一个数据域为x的新结点*p,并令结点*p的指针域指向新结点,新结点的指针域指向结点ai。从而实现三个结点ai-1,x和ai之间的逻辑关系的变化。

new=malloc ( );

new.data=x ;

new.next=p->next ;

p.next=new;


x

在已知结点之后插入结点示意图


四、删除运算

删除运算是将表的第i个结点删去。因为在单链表中结点ai的存储地址是在其直接前趋结点ai-1的指针域next中,所以首先找到ai-1的存储位置p,然后令p–>next指向ai的直接后继结点,即把ai从链上摘下。最后释放结点ai的空间,将其归还给“存储池”。


1、删除已知结点的后继结点

删除*p结点的后继结点示意图

p


2、在单链表上删除第i个元素

在单链表上删除第i个元素的算法:

int delete node ( int ; LINKLIST * head )

{ LINKLIST * p , *q ;

int j , r ;

r=1

j=0

p=head ;

while ( (j<i) && (p->next !=NULL ) )

{p=p->next ; j++ ; }

if ( p->next =NULL || j>i-1 ) /*i<1 , 比表的头位置还小*/

r=0 ;

else

{ p=p->next ; p->next=q->next ;

free (q) ; }

return r ;


3 1 2

an

head

head

a1

3.1.2.循环链表

循环链表是一种首尾相接的链表。将单链表的终点的指针改为指向单链表的第一个结点,就成为单链循环链表。

带头结点的非空循环链表

带头结点的空循环链表


an

a1

rear

特点:从表中任一结点出发均可找到表中其他所有结点。

因实际需要,经常采用尾指针表示循环链表,这样a1=rear->next->next,an=rear,显然,查找a1和an都很方便。

rear->next->next

用尾指针表示的非空循环单链表


3 1 3
3.1.3 双向链表

概念:在链表的结点中设定两个结点指针域,使链表中有两条不同方向的链,称为双向链表。

数据结构:

typedef struct dnode

{datatype data ;

struct dnode * prior ,* next;

} DLINKLIST ;

双向链表中结点的结构:


与单链表类似,双向链表也由头指针唯一确定,将头结点与尾结点链起来构成循环链表称双向循环链表。

双向链表特点:双向链表是一种对称结构,克服了单链表上指针单向性的缺点,既有前向链,又有后向链,这就使得数据元素的插入、删除操作都很方便。

建双向链表后,有

p= ( p->prior ) ->next= ( p->next ) ->prior


x

1、双向链表中插入结点

与单链表的插入和删除操作不同的是,在双链表中插入和删除必须同时修改两个方向上的指针。

插入结点示意图


算法如下:

t=malloc ( ) ;

t->data=x ;

t->prior = p->prior ;

t->next = p ;

( p->prior ) ->next= t;

p->prior = t;


P

2、双链表中删除p指针指向的结点

删除双链表中已知结点*P


双链表中删除p指针指向的结点的算法:

p->prior->next= p->next ;

p->next->prior = p->prior ;

free ( p );


3.2线性表的顺序和链式存储结构的比较

1、空间性能的比较

顺序表的存储空间是静态分布的,链表的存储空间是动态分布的。与其它链式存储一样,没有溢出现象。但要牺牲一部分附加空间。

2、时间性能比较

顺序表是随机存储结构,其时间复杂度为O(1),若链表中的操作主要查找、读取时,采用顺序表结构为宜,而操作为删除、插入元素占多时,采用链表比较合适。它不存在搬家问题。


3.3应用举例及分析

例3.1 写出一个计算链表中结点个数的算法,并依次打印出链表中元素的值。

算法如下:

Int count (LINKLIST *head)

{int i=0;

LINKLIST *p;

p=head->next;

while(p!=NULL)

{i++;

printf(“%c”,p->data);

p=p->next;}

return i;

}


3.2 写一算法,将值为x的结点插在链表中第一个值为a的结点之后,如果值为a的结点不存在,则插入在表尾。

其算法如下:

Void ifinsert (DATATYPE2 x, DATATYPE2 a,LINKLIST *head)

{LINKLIST *p_new,*p;

int flag=1;

p_new=malloc(sizeof(LINKLIST));

p_new->data=x;

p=head;

while(p->data!=NULL && flag)

{if (p->data==a)

{p_new->next=p->next; p->next=p_new;

flag=0;}

else

p=p->next;}

if(flag)

{p->next=p_new;

p_new->next=NULL;} }


3.3在一个非递减有序顺序表中,插入一个值为x的元素,使插入后的顺序表仍为非递减有序表,用带头结点的单链表结构编写算法。其算法为:

insert_order(DATATYPE2 x, LINKLIST * head)

{

LINKLIST * pr, * pn;

pr = head; pn = head->next;

While(pn ! = NULL && pn-> data < x)

{pr = pn;

pn = pn->next;}

insertafter(x,pr);

}


3.4将一个用单链表存储的线性表T=(a1,a2,…,am-1,am)置换成(am,am-1,…, a2, a1,),实现的算法中辅助变量只能用指针(单链表不带头结点)。其算法如下:

LINKLIST * inverlink(LINKLIST * head)

{

LINKLIST * p, * q, * r;

q = NULL;p = head;

While(p ! = NULL)

{r = q; q = p;

p = p->next;

q->next = r;}

return q;

}


L

a

b

c

d

例3.5 写出下列双向链表中逻辑交换结点a和b的算法,不设辅助结点,只设辅助指针。

p = L->next;

L->next = p->next;

(L->prior)->next = p;

p->prior = L->prior;

(p->next)->prior = L;

L->prior = p;

p->next = L;

L = p;


a

b

c

d

L

例3.6 写出下列双向链表中逻辑交换结点a和b的算法,不设辅助结点,只设辅助指针

p = L->next;L->next = p->next;

(L->prior)->next = p;p->prior = L->prior;

(p->next)->prior = L;

L->prior = p;p->next = L;

L = p;


习题

3.1 分析单链表、循环链表和双向链表的相同点和不同点,及各自特点。

3.2 设有两个线性表A和B皆是单链表存储结构,同一个表中的元素各不相同,且递增有序。写一算法,构成一个新的线性表C,使C为A和B的交集,且C中元素也递增有序。

3.3 设有两个按元素值递增有序的单链表A和B,编一程序将A表和B表归并成一个新的递增有序的单链表C(值相同的元素均保留在C表中)。

3.4 设L为带头节点的单链表,按下面两种情况分别编写算法删除表中值相同的多余元素。

(1)顺序表,元素值递增有序;

(2)顺序表,元素值无序。


ad