双向链表数据结构链表
算法 2 单链表的插入 int insert_link( LinkList list, PNode p, DataType x ) 算法 3 单链表结点的删除 int delete_link(LinkList list, DataType x )
数据结构 算法1 创建空单链表
链表
分析:申请一表头结点的存储空间,并将该结点指针域置空 list
{
PDoubleNode head; } CDoubleList cdlist ;
循环双链表有如下性质: p==p->rlink-llink==p->llink-rlink
数据结构 单链表应用举例
链表
【例2.4】 有一线性表的单链表表示 (a1,a2,… ,an) ,设计一算法将该单链表 逆置成逆线性表(an,an-1,… ,a1)。 算法思路:首先将单链表拆开成一个空表H和一个不带头结点的单链表,然后 将不带头结点的单链表从第一个结点开始依次取出每个结点,将其插入到H单 链表的第一个位置。算法如下: void reverse_LinkList (Linklist H) { LinkList p; p=H->next; /*p指向第一个数据结点*/ H->next=NULL; /*将原链表置为空表H*/ while (p) { q=p; p=p->next; q->next=H->next; /*将当前结点插到头结点的后面*/ H->next=q;
值域
指针域
p
data
next
数据结构
链表
3、头结点的概念与作用
为使运算简单,可以在单链表的第一个结点之前另加一
个结点,称之为头结点。头结点的data字段可以存放与整 个链表相关的信息(例如元素个数等),也可以不存任何
信息,头结点的link字段指向第一个结点,如图3所示。
list
头结点
A
B
….
F
图3 带头结点的单链表
数据结构
链表
双向链表类型声明
struct DoubleNode ; typeef struct DoubleNode *PDoubleNode; struct DoubleNode /* 双链表结点结构 */ { DataType data; pDoubleNode llink, rlink; }; struct DoubleList /* 双链表类型 */ { PDoubleNode head; /* 指向第一个结点 */ PDoubleNode rear; /* 指向最后一个结点 */ }; typedef struct DoubleList * PDoubleList; PDoubleList pdlist; /* pdlist是指向双链表类型 的指针变量 */
k0
插入x至palist[p]
k1 p k2 x k3
k4
k5 k6
表已满!
数据结构
链表
顺序表的删除过程 int delete_seq( PSeqList palist, int p) k0 k0 k1 k2 p k3 k4
k1
p
k2 x3 k
k4 3 k5 4
删除位置p的元素
p
k5
k6
表长减1
k6 5 k6
B
105
C
110
数据结构 线性表h=(A,B,C,D,E,F)的 链式存储结构如图1所示。 h 由于这种链表中,每个结
链表
点只有一个指针域,故又称为
单链表。指向链表中第一个结 点的指针,称为这个链表的头
指针(h)。
图1
线性表h的链式 存储结构
数据结构
链表
h
在讨论链表时,主要关心的 只是线性表中元素之间的逻辑顺 序,而不是每个元素在存储器中 的位置,所以通常可把图1的单 链表,更加直观地表示成图2所 示的用箭头相链接的结点序列, 其中h代表头指针。
注:设置表头结点的目的是统一空链表与非空链表的操作,简化链表操 作的实现。带头结点的空链表表示为:list->next==NULL;而不带头结点 的空链表只能表示为list==NULL;
数据结构
链表
4、单链表的常用算法(带头结点)
算法 1 创建空单链表
LinkList createNullist_link( void )
} /*while*/
}
数据结构
链表
【例2.5】假设有两个元素值递增有序的线性表A和B,均以
带头结点的单链表作为存储结构,编写算法将A和B归并成 一个按元素值递增有序排列的线性表C,并要求利用原线
性表A和B的结点空间存放线性表C。
算法思路:利用A、B两表有序的特点,依次扫描A和B的元 素,比较当前的元素的值,将当前值较小者摘下,插入到 C表的尾部,如此直到一个单链表扫描完毕,然后将未完 的那个单链表中余下部分连到C即可。
在顺序表中,逻辑关系上相 邻的两个结点,在物理上也是相 邻的,故可以按下标随机存取任 一元素,
1006
数据结构 顺序表的插入过程 int insert_seq( PSeqList palist, int p, DataType x ) palist[8]
链表
p
k0 k1 k2 k3
k4 3 k5 4 k6 5 k6
储单元,存储线性表的各个元素,为了表示每个元素与其后 继元素之间的逻辑关系,每个元素除了需要存储自身信息外,
还要存储一个指示其后继元素的信息,即后继元素的地址。
这样每个结点包括两个域:值域(data)----存放元素本身
的信息;指针域(link)----存放其后继结点的存储位置。
值域 指针域
例
A
100
注:算法中malloc为内存申请函数,需头文件stdlib.h支持。
数据结构
链表
算法2 单链表的插入(在list 带有头结点的单链表中,在p 所指结点后面插入元素x)
list
A
p
B
②
C
q X ^
①
D
^
②p->next=q;
① q->next=p->next;
list
A
p
B
q
X
C
D
^
图6 插入结点示意图
else
r->next=q; /*将B表剩余部分插入到C表的尾部*/
} /*end*/
数据结构
链表
应用举例—Josephus问题*
问题描述:
设有 n 个人围坐在一个圆桌周围,现从第 s 个人 开始报数,数到第 m 的人出列,然后从出列的下一 个人重新开始报数,数到第m的人又出列,…,如此 反复直到所有的人全部出列为止。Josephus问题是: 对于任意给定的n,s和m,求出按出列次序得到的n个 人员的序列。 现以n=8,s=1,m=4为例,问题的求解过程如图 2-15所示。图中s1指向开始报数位置, 若初始的顺 序为 n1,n2,n3,n4,n5,n6,n7,n8。则问题的解 为n4,n8,n5,n2,n1,n3,n7,n6。
int josephus_ SeqList (PSeqList josephus_seq, int s, int m)
数据结构
链表
r=C;
free(B); /*释放B表的头结点*/ while (p&&q) { if (p->data<q->data) { s=p; p=p->next; } else { s=q; q =q->next; } /*从原AB表上摘下较小者*/ s->next=r->next; r->next=s; r=r->next; } /*while*/ if (p) r->next=p; /*将A表剩余部分插入到C表的尾部*/ /*插入到C表的尾部*/
^
LinkList CreateNullist_link(void) { LinkList list=(LinkList)malloc(sizeof(struct Node)); //申请表头结点存储空间 if( list != NULL) list->next=NULL; else printf(“Out of space!\n”); //创建失败 return(list); }
LinkList merge_LinkList (LinkList A, LinkList B) { /*设A、B均为带头结点的单链表*/ LinkList C; LinkList p,q,r; p=A->next; q=B->next; C=A; /*借助A表的头结点构造空C表*/ C->next=NULL;
注:图中用“^”表示空指针,在算 法中用NULL表示。
h
A 图2
B
C
D
E
F ^
单链表h的逻辑结构示意图
数据结构
链表
2、单链表的类型定义
typedef struct Node *PNode; /* 结点指针类型 */ struct Node /* 单链表结点结构 */ { DataType data; /* 值域 */ struct Node *next; /* 指针域 */ }; 为提高可读性,可定义单链表类型如下: typedef struct Node *LinkList; LinkList list; /* 定义一单链表list */ PNode p; /* 定义一单链表结点指针*/ 则指针p所指结点的两个域表示为: 值 域: p->data 指针域: p->next
数据结构
链表
Josephus问题
n8 n7 n6
n1
S=1; m=4;
n2 n3 n4 n5