第三章 链表

合集下载
相关主题
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第三章 链表
插 入 算 法 续
} }
while(p!=NULL && j<i) { j++ p=p->next; } if(p!=NULL) /*把新结点插入其后*/ { s->next=p->next; p->next=s; } else printf(“未找到!\n”);
第三章 链表
3. 删除
第三章 链表
链 堆 栈 的 出 栈 算 法
int pop(node *top) { int x; node *p; if(top==NULL) printf(“栈为空!\n”); else { x=top->data; p=top; top=top->next; free(p); return(x); } }
第三章 链表
3. 单链表的类型定义
假设线性表中数据元素的类型为datatype,单
链表的类型定义如下:
typedef struct node * pointer; struct node { datatype data; pointer next; }; typedef pointer linklist;
head
第三章 链表
1. 带头指针的循环链表
通常在循环链表的表头结点前面再加一个空结点,
也叫空表头结点。 表空时空表头结点的指针指向其本身,如下面的 图所示为空循环链表。 空表头结点除指针以外的数据域是没有用的,但 为了将此结点与一般结点相区别,常常是将其赋 以一个特别的数据,以与一般结点相区别。
第三章 链表

链堆栈的入栈算法
在栈顶指针是top的链堆栈中插入一个值为x
的结点的算法:
void push (node *top, int x) { node *s; s=(node *)malloc(sizeof(node)); /*建立一个结点指针*/ s->data=x; s->next=top; top=s; }
void insert (node *head, int i, x) { node *s,*p; int j; s=(node * )malloc(sizeof(node)); /*生成新结点*/ s->data=x; if(i==0) /*如果i=0,则将s所指结点插入到表头*/ { s->next=NULL; head=s; } else { p=head; j=1; /*查找第i个结点,由p所指向*/
(p->prior) ->next=p->next; (p->next) ->prior=p->prior;
这两个语句的执行顺序可以颠倒,执行这两个
语句之后,可调用free(p),将*p结点释放。
p ①

第三章 链表
返回
3.3.1 链堆栈
链堆栈是栈的链接
存储表示,它是只 top 允许在表头进行插 入和删除运算的单 链表。 它与普通的单链表 没有什么不同,只 是将头指针head改 称为栈顶指针top。


熟练掌握以下内容: 单链表的结构特点、基本运算并能设计简单算法 循环链表的结构特点、基本运算并能设计简单算法 双链表的结构特点、基本运算并能设计简单算法 了解以下内容: 用十字链表表示稀疏矩阵 链接堆栈,链接队列的应用以及一元多项式加法的 应用实例
第三章 链表
第三章目录
单链表及其运算 3.2 循环链表与双向链表 3.3 链表应用举例 3.4 表示稀疏矩阵的十字链表 3.5 应用举例及分析 小 结 习题与练习
数据结构
第三章 链表
第三章 链表

识点
单链表的结点形式、组织方法和特点 单链表的基本运算和相应的算法 循环链表的组织方法和基本运算算法 双链表的结点形式、组织方法和特点 双链表的基本运算和相应的算法 顺序表与链表比较,各自的优、缺点 链表的应用 用十字链表表示稀疏矩阵
第三章 链表


双链表插入、删除运算的算法 利用链接结构的特点设计有效算法,解决与链表结 构相关的应用问题
指向其前一个结点的指针,这样形成的链表中 有两条不同方向的链,因此从某一结点均可向 两个方向访问。 双链表的结点形式为:
prior
data
next
其中链域prior和next分别指向本结点的直接前 趋和直接后继结点。
第三章 链表
如果循环链表的结点再采用双向指针,
就成为双向循环链表。
head
第三章 链表
算法分析
此算法的关键是while循环语句,开始时p
指针指向头结点,每一循环都修改指针 值,让它指向下一个结点,同时将计数 链表长度的变量count加1。 这样每循环一次就向后推移一个结点, 直到p所指结点*p的链域值为NULL为止。 空指针NULL起标志的作用,若无此标志, 尾结点链域的值为“无定义”,上述算 法中的while语句在做最后一次判断时将 出现“运行错”,这是应予避免的。
当需要从单链表上删除结点时,就要通过删
除运算来完成。 删除单链表上一个其值为x的结点的主要操作 是:
1) 用遍历的方法在单链表上找到该结点; 2) 从单链表上删除该结点。
欲从单链表上删除一个结点,需修改该结点
的前一个结点的指针,如下面的图所示。
第三章 链表
q
p
head
x

假设指针q指向待删除结点的前一个结点,指 针p指向要删除的结点,删除该结点的操作如 下:将该结点的前一个结点*q的链域指向*p 的后继结点(即q->next=p->next)。
head
第三章 链表
2. 带尾指针的循环链表
另一种方法是不设头指针而改设尾指针,这
样无论是找头结点还是尾结点都很方便。因 为尾结点由尾指针rear来指示,则头结点的 位置是rear->next->next。 rear
rear
第三章 链表
3.2.2 双链表
Байду номын сангаас向链表中每个结点除了有向后指针外,还有
第三章 链表
P
head
a1
a2
ai
ai+1
an

S
x
假设指针p指向单链表中的第i个结点,指针s指向 已生成的新结点,链入新结点的操作如下:
将新结点*s的链域指向结点*p的后继结点 (即s->next=p->next); 将结点*p的链域指向新结点(即p->next=s)。
第三章 链表
插 入 算 法
1.
第三章 链表
计 算 结 点 个 数 算 法
int length(node *head) /*求表head的长度*/ { int count=0; /*计数器置初值*/ node *p=head; /*p指向头结点*/ while (p!=NULL) { p=p->next; count++; } return(count); /*返回表长值*/ }
第三章 链表
3.3.2 链队列
链队列需要两个指针,其中队首指针front指向
链表的表头,队尾指针rear指向链表的表尾。 一般插入时只修改队尾结点的指针和队尾指针 rear,删除时只修改队首指针front。当将第一个 元素插入空队列或删除了最后一个元素而使队 列为空时,front和rear都需要修改。
第三章 链表
1. 双链表的插入
设要在p所指结点的前面插入一个新结点
*q,则需要修改4个指针 :
q->prior=p->prior; q->next=p; (p->prior)->next=q; p->prior=q;
p
① q
第三章 链表



2. 双链表的删除
设p指向待删除的结点,则删除该结点步骤为:
第三章 链表
2. 单链表
所有结点通过指针的链接而构成的线性表称为
单链表。线性表(a1,a2,……an,)的单链表 可直观地画成:
head a1 a2 ai an ∧
head是单链表的头指针,指向开始结点a1, an是
终端结点,其指针域为空,不指向任何结点。 一个单链表由头指针head唯一标识和确定,因 此,可用头指针来命名单链表。
返回
3.2.1 循环链表
循环链表(circular linked
list)是一种首尾相 接的链表,将单链表表尾结点原来的空指针 改为指向表头结点,就成为循环链表。 循环链表并不多占存储单元,但从循环链表 的任一个结点出发都可以访问到此链表的每 一个结点,因为当访问到表尾结点后又能返 回到头结点。
第三章 链表
2. 插入
所谓插入是指在单链表中第i个结点(i≥0)之后
插入一个元素为x的结点。 实现插入算法主要完成三个基本操作:
1) 在单链表上找到插入位置,即找到第i个结点。 可以用遍历的方法,即从表头起顺次访问单链 表的结点,直至找到第i个结点。 2) 生成一个以x为值的新结点。 可通过C的库函数malloc(size)来产生。 3) 将新结点链入单链表中。 需要改变相关结点的指针 ,如下面的图所示。
一个结点是由两个域data和next组成的记
录,data是结点的数据域,next是结点的链域。
第三章 链表
4. 指针的概念
假设p是一个pointer类型,应正确区分指针型
变量、指针、指针所指的结点和结点的内容 这四个密切相关的不同概念:
p的值(如果有的话)是一个指针,即是一个所指 结点的地址 。 该指针(若不是NULL)指向的某个node型结点 用*p来标识。 结点 *p是由两个域组成的记录,这两个域分别用 pdata域和pnext域来标识,它们各有自己的值, pdata的值是一个数据元素,pnext的值是一个 指针。
第三章 链表
删 除 算 法
void delete(node *head, int x) { node *p, *q; if (head==NULL) printf(“链表下溢!\n”); /*判空*/ if(head->data==x) / *如表头结点值等于x*/ { p=head; head=head->next; free(p); } else { q=head; /*从第二个结点开始查找*/ p=head->next;
链队列删除算法
int delete(node *front,rear) { node *p; int x; if (front==NULL) printf(“空队列!\n”); else { x=front->data; p=front;
第三章 链表
3.1.2 单链表的基本运算
遍历(Traversal):根据已给的表头指针, 按由前向后的次序访问单链表的各个结点。 在实际应用中遍历是对单链表的最基本运 算,例如,当要打印或显示出各个结点的 数值域值、计算单链表的长度(即结点数目) 或寻找某一个结点时都需要遍历单链表。 假设head是单链表的头指针,计算一个已 建立好的单链表的结点个数的算法如下:
第三章 链表
双链表较单链表虽然要多占用一些存储单元,
但对其插入和删除操作以及查找结点的前趋和 后继都非常方便。 双链表结构是一种对称结构,设指针p指向双 链表的某一结点,则双链表的对称性可用下式 来表示: p=(p->prior)->next=(p->next)->prior 即结点*p的地址既存放在其前趋结点 *(p->prior)的后继指针域中,又存放在它的后 继结点*(p->next)的前趋指针域中。
front rear

第三章 链表
链 队 列 插 入 算 法
void insert(node *front, rear, int x) { node *s; s= (node *) malloc (sizeof (node)); s->data=x; s->next=NULL; if (rear ==NULL) /*处理空队列的情况*/ { front=s; rear=s; } else { rear->next=s; rear=s; } 第三章 链表 }
第三章 链表
删 除 算 法 续
}
while(p!=NULL && p->data!=x) { q=p; p=p->next; } if(p!=NULL) /*找到该结点,删除*/ { q->next=p->next; free(p); } else printf(“未找到!\n”); }
第三章 链表
3.1
第三章 链表
3.1.1 单链表

1. 结点: 在链式存储结构中,结点不仅存放数 据元素的值,还附加一个指针(链),用来指 向该结点的直接后继结点。
data
next

其中,data部分称为数据域,用于存储线性表 的一个元素,next部分称为指针域或链域,用 于存放一个指针,即存放该结点的直接后继结 点的地址。
相关文档
最新文档