数据结构(二):链表、链队列

摘要:
上一篇博文中主要总结线性表的顺序存储结构实现,比如顺序表、顺序队列和顺序栈。循环链表最后一个结点的link指针不为NULL,而是指向了表的前端为简化操作,在循环链表中往往加入表头结点。但对于指数不全的多项式不经济多项式的链表表示在多项式的链表表示中每个结点三个数据成员优点:多项式的项数可以动态地增长,不存在存储溢出问题,插入、删除方便,不移动元素。

上一篇博文中主要总结线性表的顺序存储结构实现,比如顺序表、顺序队列和顺序栈。具体可以参考上篇博文

http://blog.csdn.net/lg1259156776/article/details/46993591

下面要进行学习和总结的是线性表的链式存储结构实现,比如链表和链队列。

顺序存储结构的优缺点
优点是逻辑相邻,物理相邻,可随机存取任一元素,存储空间使用紧凑;缺点是插入、删除操作需要移动大量的元素,平均移动n/2,预先分配空间需按照最大空间分配,利用不充分(C++ STL模板库中实现的vector的存储空间是由类自动分配,无需用户管理,伴随着插入和删除,其容量也总是会调整的,这个内存维护总是需要花费心思的),表容量难以扩充。
链表

单向链表

每个元素(表项)由结点(Node)构成

typedef struct LNode

{

Datatype data;

struct LNode *next;

}

数据结构(二):链表、链队列第1张

线性结构
数据结构(二):链表、链队列第2张

单向链表的存贮映像

数据结构(二):链表、链队列第3张

对应的指针操作

LNode *p,*q;
p->data;p->next;
q=new LNode;
q=p;
q=p->next; (q指向后继)
p=p->next; (指针移动)
p->next=q; (链指针改接)
p->next= q->next;
链表结点的基本运算
Void SetNode(LNode *front);//构造函数,结点的next置NULL
Node*NextNode(LNode *ptr);//返回后继指针
Void InsertAfter(LNode *ptr,Datatype item);//在结点*ptr插入
Void DeleteAfter(LNode *ptr);//删除结点后的一个结点.
在结点后插入数据指针的变化:

newnode->next= current->next;

current->next = newnode

数据结构(二):链表、链队列第4张

Void InsertAfter(LNode *ptr,Datatypeitem)

{

LNode*q;

q=new LNode;

If (q==NULL){错误信息}

q->data=item;

q->next=ptr->next;

ptr->next=q;

}
在结点后删除数据指针的变化

q=p->next;

If(q!=NULL){p.next=q.next;Deleteq;}

数据结构(二):链表、链队列第5张

单链表的定义

多个类表达一个概念(单链表):链表结点(ListNode)、链表(List)

Typedef struct

{

LNode *front;

int Size;//并非必要的成员

} LList;

Void SetLList(LList *L);
Void FreeList(LList *L);
lnt LListSize(LList *L);
lnt LListEmpty(LList *L);
lnt LListLocate(LList *L,DataType item);
。。。。
求线性表的长度
int LListSize(LList *L)

{

Lnode *p=L;

int k=0;

while(p){k++,p=p->next;}

return k;

}//时间复杂度O(n)

关于插入的讨论
已知结点之后插入,时间复杂度O(1)
已知结点之前插入?

需要查找前驱,时间复杂度为O(n),如果指向第一个结点,要修改头指针

Void LListInsertB(LList *L,LNode *p,LNode *s)

{

LNode *q;

if(p==L){s->next=L;L=s;}

else { q=L;

while(q->next!=p)q=q->next;

q->next=s;s->next=p;

}

}

带表头结点的单链表

表头结点位于表的最前端,本身不带数据,仅标志表头
设置表头结点的目的是统一空表与非空表的操作,简化链表操作的实现
头结点:表中的第一个结点,数据域为空
最后一个结点的指针为 NULL
开始结点:第一个数据元素的结点
头指针:指向头结点的指针
数据结构(二):链表、链队列第6张数据结构(二):链表、链队列第7张

设置表头结点的目的是统一空表与非空表的操作,简化链表操作的实现

带表头结点的单链表插入
在带表头结点的单链表第一个结点前插入新结点

Newnode->next=p->next ;p->next=newnode

数据结构(二):链表、链队列第8张数据结构(二):链表、链队列第9张

从带表头结点的单链表中删除第一个结点

q= p->link;p->link = q->link;delete q;

数据结构(二):链表、链队列第10张

Void LListSetData(LList *L,Datatypeitem,int pos)

{

int i;LNode *ptr;

如果pos不合法,退出

否则

ptr=NextNode(L->front);

for(i=0;i<pos;i++)

ptr=NextNode(ptr);

ptr->data=item

}

循环链表

循环链表是单链表的变形。
循环链表最后一个结点的link指针不为NULL,而是指向了表的前端
为简化操作,在循环链表中往往加入表头结点。
循环链表的特点是:只要知道表中某一结点的地址,就可搜寻到所有其他结点的地址。
数据结构(二):链表、链队列第11张

特殊链表

链表队列

Typedefstruct

{

LNode *front;

LNode *rear;

}LQuene;

数据结构(二):链表、链队列第12张

voidSetLQuene( LQueue *Q )

{

Q->front=new LNode;

if(Q->front==NULL){err;}

SetNode(Q->front);

Q->rear=Q->front;

}

void EnQueue (LQueue *Q, DataType item)

{

InsertAfter(Q->rear,item);

Q->rear =NextNode(Q->rear) ;

}

void OutQUEUE(LQueue *Q )

{

if (EMPTY( Q ) ){error;}

else{

temp = Q->front->next ;

Q->front->next =temp->next ;

delete temp ;

if( Q->front->next == NULL )

Q->rear = Q->front ;

}

}

多项式的存储表示
非常简单的可以想到一下两种表示存储表示:

静态数组

int degree;

float coef[maxDegree+1];

动态数组

typedef struct

{

int degree;

float *coef;

}Polynomial;

构造函数:

VoidSetPoly ( Polynomial *poly,int sz ) {

Poly->degree= sz;

Poly->coef= new float [degree + 1];

}

以上两种存储表示适用于指数连续排列的多项式。但对于指数不全的多项式不经济

多项式的链表表示

在多项式的链表表示中每个结点三个数据成员

数据结构(二):链表、链队列第13张

优点:多项式的项数可以动态地增长,不存在存储溢出问题,插入、删除方便,不移动元素。
基本操作
Polynomial( ); //构造函数
int IfZeroPoly ( ); //判是否零多项式
float Coef ( int e); // 返回某次数的系数
int MaxExp ( ); //返回最大指数
PolynomialAdd (); // 加法
PolynomialMinus(); // 减法
PolynomialMult (); // 乘法
float Eval ( float x); //求值

*************************************************************************************************************************************

2015-7-23

免责声明:文章转载自《数据结构(二):链表、链队列》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Selenium中日期控件的操作懒加载下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

C#内存管理与垃圾回收

垃圾回收还得从根说起,就像生儿育女一样。 根:根是一个位置,存放一个指针,该指针指向托管堆中的一个对象,或是一个空指针不指向任何对象,即为null。根存在线程栈或托管堆中,大部分的跟都在线程栈上,因为定义的变量就存在线程栈上,类型对象指针存在托管堆中,因为实例化一个对象要额外分配两个字段“类型对象指针”和“同步块索引”。   类型对象指针的作用。实例化一个...

关于malloc和sizeof的用法

问题1: 1.L.elem = (ElemType *)malloc(LIST_INIT_SIZE*sizeof(ElemType));2.newbase = (ElemType *)realloc(L.elem,(L.listsize+LISTINCREMENT)*sizeof(ElemType)); 其中L是已经定义的线性表,LIST_INIT_SIZ...

C++ | 虚函数表内存布局

虚表指针 虚函数有个特点。存在虚函数的类会在类的数据成员中生成一个虚函数指针 vfptr,而vfptr 指向了一张表(简称,虚表)。正是由于虚函数的这个特性,C++的多态才有了发生的可能。 其中虚函数表由三部分组成,分别是 RTTI(运行时类型信息)、偏移及虚函数的入口地址。而虚表与类及类生成的对象有存在着以下两种关系: 类与虚表的关系:一个类只有一个...

标准C程序设计七---32

Linux应用 编程深入 语言编程标准C程序设计七---经典C11程序设计以下内容为阅读:《标准C程序设计》(第7版) 作者:E. Balagurusamy(印), 李周芳译 清华大学出版社 2017.7《21天学通C语言》(第7版) 作者:Bradley Jones Peter Aitken Dean Miller(美), 姜佑译 人民邮电出版社 201...

Linux 内核 hlist 详解

在Linux内核中,hlist(哈希链表)使用非常广泛。本文将对其数据结构和核心函数进行分析。 和hlist相关的数据结构有两个:hlist_head 和 hlist_node //hash桶的头结点struct hlist_head {   struct hlist_node *first;//指向每一个hash桶的第一个结点的指针};//hash桶的...

Android JNI和NDK学习(08)JNI实例一 传递基本类型数据

Android JNI和NDK学习(08)--JNI实例一 传递基本类型数据 本文介绍在Java和JNI之间相互传递基本数据类型的方法。 由于前面已经详细介绍搭建和建立NDK工程的完整流程(参考“静态实现流程”或“动态实现流程”),这里就不再介绍流程;而是将重点放在说明如何实现Java和JNI之间相互传递基本数据。 1 建立eclipse工程 建立工程Nd...