分享
 
 
 

数据结构学习笔记(2)partII

王朝other·作者佚名  2006-01-31
窄屏简体版  字體: |||超大  

三.线性表类型的实现——链式映象

1.单链表定义:用一组地址任意的存储单元存放线性表种的元素,以元素(数据的映象)+指针(指示后继元素存储位置的)= 结点(表示数据元素)

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

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

2.单链表的C语言描述

Typedef struct Lnode{

ElemType data; //数据域

Struct Lnode *next //指针域

}Lnode, *LinkList;

1. 操作的实现

a. 线性表的操作GetElem(L, i, &e)

在链表中的实现:

基本操作为:使指针p始终指向线性表中第j个数据元素

status GetElem_L(LinkList L, int pos,

ElemType &e)

{

p = L->next; j = 1; //初始化,p指向第一个结点,j为计数器

while(p && j<pos){p =

p->next; ++j;}

//指针向后查找,直到p指向第pos个元素或p为空

if(!p || j>pos)

return ERROR; //第pos个元素不存在

e = p->data; //取第pos个元素

return OK;

}

时间复杂度O(ListLength(L))

b. 线性表的操作ListInsert(&L, i, e)

在链表中的实现:

基本操作:找到线性表中第i-1个结点,修改其指向后继的指针

有序对<a(i-1), a(i)>变为<a(i-1), e>和<e, a(i)>

status ListInsert_L(LinkList L, int

pos, ElemType e)

{

p = L; j=0;

while(p&& j<pos-1)

{p= p->next; ++j;} //寻找第pos-1个结点

if(!p || j>pos-1)

return ERROR; //pos小于1或者大于表长

s = (LinkList)malloc(sizeof(LNode));

//生成新结点

s->data = e;

s->next = p->next; //插入L中

p->next = s;

return OK;

}

时间复杂度O(ListLength(L))

c. 线性表的操作ListDelete(&L, i, &e)

基本操作:找到线性表中第I-1个结点,修改其指向后继的指针

有序对<a(i-1), a(i)>变为<a(i), a(i+1)>和< a(i-1), a(i+1)>

status ListDelete_L(LinkList L, int

pos , ElemType &e)

{

p = L;

j= 0;

while(p->next &&

j<pos-1)

{p = p->next; ++j;} //寻找第pos个结点,并令p指向其前驱

if(!(p->next) || j>pos-1)

return ERROR; //删除位置不合理

q = p->next;

p->next = q->next; //删除并释放结点

e = q->data;

free(q);

return OK;

}

时间复杂度O(ListLength(L))

d.线型表的操作:建立链表CreateList_L(….),从后往前建立链表

void CreateList_l(LinkList& L, int n)

{

L = (LinkList)malloc(sizeof(LNode));

L->next = NULL; //先建立一个带头结点的单链表

for(i = 0; i>0; --i)

{

p = (LinkList)malloc(sizeof(LNode));

scanf(&p->data); //输入元素值

p->next = L->next; //插入到表头

L->next = p;

}

}

时间复杂度:O(ListLength(L));

e.线型表的操作:删除链表ListDelete_L(LinkList

L, int pos, ElemType &e)

{

p = L;

j = 0;

while(p->next && j< pos-1) //寻找第pos个结点,并令p指向其前驱

{

p = p->next;

++j;

}

if(!(p->next) || j>pos-1) //删除位置不合理

return ERROR;

q = p->next; //删除并释放结点

p->next = q->next;

e = q->data;

free(q);

return OK;

}

时间复杂度:O(ListLength(L));

对链表操作的最重要的就是一个指向结点的指针和一个计数器。

用线型表表示集合,应首先尽量对集合进行排序,提高运行效率。

用上述定义的单链表实现线型表的操作时,存在问题:

1. 链表的表长是一个隐含的值;

2. 在单链表的最后一个元素最后插入元素时,需遍历整个链表;

3.在链表中,元素的“位序”概念淡化,结点的“位置”概念强化。

改进链表的设置:

1.

加“表长”,“表尾指针”和“当前位置的指针”三个数据域

2.

基本操作由“位序”改为“指针”

四.一个带头结点的线型链表类型

typedef struct LNode{ //结点类型

ElemType data;

Struct LNode *next;

}*Link, *Position;

结点的基本操作:

status MakeNode(Link &p, ElemType e);

//分配由p指向的值为e的结点,并返回OK;

//失败,返回ERROR

void FreeNode(Link& p); 释放p指向的结点

typedef struct{ //链表类型

Link head , tail; //指向头结点和最后一个结点

Int len; //链表的长度

Link current; //指向当前访问的结点的指针,初始位置指向头结点

} LinkList;

链表的基本操作:

status InitList(LinkList& L);

//构造一个空的线型链表L,头指针,尾指针和当前指针均指向头结点,表长0

status DestroyList(LinkList& L);

//销毁线型链表L

引用操作:

status ListEmpty(LinkList L); //判表空

int ListLength(LinkList L); //求表长

status Prior(LinkList L); //改变当前指针指向其前驱

status Next(LinkList L); //改变当前指针指向其后继

ElemType GetCueElem(LinkList L); //返回当前指针所指的数据元素

Status LocatePos(LinkList L, int I); //

Status LocateElem(LinkList L, ElemType e, status(*compare)(ElemType,

ElemType)); //若存在与e

//满足函数判定关系的选素,则移动当前指针到第一个满足条件

//的元素,并返回OK;否则,返回ERROR

Status ListTraverse(LinkList L, status (*visit)()); //依次对每个元素调用函数visit

加工型操作:

status ClearList(LinkList& L); //重置为空表

status SetCurElem(LinkList& L, ElemType e); //更新当前指针所指数据元素

status Append(LinkList &L, Link s); //一串结点链接在最后一个结点之后

status InsAfter(LinkList &L, ElemType

e); //元素e插入到当前指针之后

status DelAfter(LinkList &L, ElemType*

e); //删除当前指针之后的结点

例如:

status InsAfter(LinkList& L, ElemType e)

{

if(! L.current) return Error;

if(! MakeNode(s, e) ) return Error;

s->next = L.current->next;

L.current->next = s;

return OK;

}

status DelAfter(LinkList& L, ElemType& e)

{

if(! (L.current &&

L.current->next) )

return Error;

q = L.current->next;

L.current->next = q->next;

e = q->data;

FreeNode(q);

return OK;

}

利用上述定义的线型链表可以完成线型表的其他操作:

例一:插入结点

status ListInsert_L(LinkList L, int I,

ElemType e)

{

//在带头结点的单链线型表L的第I个元素之前插入元素e

if(! LocatePos(L, I-1) ) return Error; // I不合法

if(InsAfter(L, e)) return OK;

//插入在第I-1个结点之后

else return Error;

}

例二,合并两个链表到第三个链表中

void MergerList_L(LinkList& La,

LinkList &Lb, LinkList& Lc, int(*compare)(ElemType, ElemType) )

{

if(! InitList(LC) ) return Error; //存储空间分配失败

LocatePos(La, 0);

LocatePos(Lb, 0); //当前指针指向头结点

If(DelAfter(La, e) ) a = e;

Else

a = MAXC; // MAXC为常量最大值

If((DelAfter(Lb, e) ) b = e;

Else

b = MAXC; // a 和b为两表中当前比较的元素

While( !(a == MAXC && b == MAXC) )

//La 和 Lb非空

{

if((*compare)(a, b) <= 0) // a <= b

{

InsAfter(Lc, a);

If(DelAfter(La, el) a = el;

Else a = MAXC;

}

else

//a > b

{

InsAfter(Lc, b);

If(DelAfter(Lb, el) b = el;

Else b = MAXC;

}

}

DestroyList(La);

DestroyList(Lb); //销毁La 和 Lb

Return OK;

}

五.其他形式的链表:

1. 双向链表:

typedef struct DuLNode{

ElemType data; //数据域

Struct DuLNode *prior;

//指向前驱的指针

Struct DuLNode *next; //指向后继的指针

}DuLNode, *DuLinkList;

2. 循环链表;

最后一个结点的指针域的指针又指向第一个结点的链表。

六.一元多项式的表示

ADT Polynomial{

数据对象:D = { a(i) | a(i) ∈ TermSet , I = 1, 2, 3,……,m,

m>0}

{TermSet

中的每个元素包含一个表示系数的实数和表示指数的整数}

数据关系:R = {< a(i-1),a(i)> | a(i-1),

a(i) ∈ D, 且a(i-1)中的指数值

< a(i)中的指数值, i = 1,2,….n}

基本操作:

CreatePolyn(&P, m);

输入m项的系数和指数,建立一元多项式P

DestroyPolyn(&P);

初始条件:一元多项式p已存在

操作结果:销毁一元多项式

PrintPolyn(&P);

初始条件:一元多项式p已存在

操作结果:打印一元多项式p

AddPolyn(&Pa, &Pb)

初始条件:一元多项式pa , pb已存在

操作结果:pa = pa + pb,并销毁pb

SubtractPolyn(&Pa, &Pb)

初始条件:一元多项式pa , pb已存在

操作结果:pa = pa – pb, 并销毁pb

MultiplyPolyn(&Pa, &Pb)

初始条件:一元多项式pa , pb已存在

操作结果:pa = pa * pb, 并销毁pb

PolynLength(&P)

初始条件:一元多项式p已存在

操作结果:返回p中的项数

}ADT Polynomial

如此定义的多项式可以看成始一个有序表,则多项式定义中的各个操作均可利用有序表操作来完成。

抽象类型数据Polynomial的实现

typedef

struct{//项的表示,多项式的项作为LinkList的数据元素

float coef; //系数

int expn; //指数

}term, ElemType; //两个类型名:term用于本ADT,ElemType为LinkList的数

//据对象名

typedef LinkList polynomial; //用带表头结点的有序链表表示多项式

int cmp(term a , term b) //比较多项式的项,a的指数值<b的指数值 返回-1

//

a的指数值 〉b的指数值 返回0

//

a的指数值 = b的指数值 返回1

例:创建一个一元多项式

void CreatePolyn(polynomial &p, int m)

{

//输入m项的系数和指数,建立表示一元多项式的有序链表P

InitList(P);

e.coef = 0.0;

e.expn = -1;

SetCurElem(P, e) //置头结点的数据元素

For(i=1; i<= m ; i++) //依次输入m个非零项

{

Scanf(e.coef, e.expn);

If(! LocateElem(P, e, (*cmp)() ) //当前链表中不存在该指数项

InsAfter(P, e); //在第一个大于插入项指数的数据项前插入

//新的数据项

}

}

七.本章小结:

了解线性表的逻辑结构特性是数据元素之间存在着线性关系,在计算机中表示的存储结构是顺序结构和链式结构。用前者表示的线性表为顺序表,用后者表示的线性表为链表。

熟练掌握这两类存储结构的描述方法,以及线性表的各种基本操作的实现。

比较两种线性表的不同特点和使用场合。当表的数据元素之间的关系不发生变化,则使用顺序表较好,反之则利用链表较好。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有