济南大学数据结构 第二章
《数据结构》课件第二章

线性表的基本操作(逻辑)
➢ 构造一个空表L ➢ 获取L的长度(即元素个数) ➢ 访问L中第i个数据元素的值 ➢ 访问L中第i个数据元素的前驱/后继的值 ➢ 在L中第i个元素之前插入新的元素e ➢ 删除L的第i个数据元素
➢ 注意在插入或者删除之后,线性表的长度应 能随之改变
一 顺序存储
➢ 线性表的顺序表示:用一组地址连续的存储单 元依次存储线性表的数据元素。
否
将Temp_b插入到 LC的第k个位置上
Temp_a ≤ Temp_b
是 将Temp_a插入到 LC的第k个位置上
否 i ≤ LA.len 否
j← j + 1
i← i + 1
j ≤ LB.len
Temp_a = Temp_b
是
否
否
j← j + 1
k← k + 1
结束
是
将LA表的第i个元 素插入到LC表的
插入操作的时间复杂度 O(n/2) 链表中的插入、删除操作没有上溢的情况, 并且节省内存资源
思考:若现已知道指向某元素节点的指针 p,希望能在该节点之前插入元素x,该如 何操作?其算法时间复杂度是多少?
3) 单链表的删除
p
删除第i个元素,由e返回值 删除b
a
Hale Waihona Puke bc … 1) 寻找第i-1个结点
2) 保留结点b的地址
9 SHI 5
0
1
1 ZHAO 2
2 QIAN 3
3 SUN 4
4 LI
9
5 ZHOU 6
6 WU 8
7 ZHENG 8
8 WANG 0
9 SHI 5
i=s[i].cur 指针后移
数据结构第二章答案课件

a1 a2
…
an e …
}
S.base
S.topS.top
Status Pop (SqStack &S, ElemType &e) {
// 若栈不空,则删除S的栈顶元素,
// 用e返回其值,并返回OK;
// 否则返回ERROR
if (S.top == S.base) return ERROR;
e = *--S.top;
1 (n 0,1)
相应的算法:
n! n * (n 1)! (n 1)
float fact(int n)
{ if (n==0||n==1) s=1;
else s=n*fact(n-1);
return s; }
若求5!,递归调用执行过程:
主函数 mani() printf(“fact(5)”)
输出 s=120.00
尽管一生只在学校里读过三个月的书但通过勤奋好学勤于思考发明了电灯电报留声机电影等一千多种成果成为著名的发明家例一数制转换例二括号匹配的检验例三表达式求值313尽管一生只在学校里读过三个月的书但通过勤奋好学勤于思考发明了电灯电报留声机电影等一千多种成果成为著名的发明家例一数制转换十进制数n和其他d进制数的转换算法基于以下原理
第一层调用
n=5 s=5*fact(4)
fact(5) =120
第二层调用
n=4 s=4*fact(3)
fact(4) =24
每一次递归调用并未立即得到
结果,而是进一步向深度递归
调用,直到n=1或n=0时,函数 fact才有结果为1,然后再一一 返回计算,最终得到结果。
第三层调用
n=3 s=3*fact(2)
例二、 括号匹配的检验
《数据结构(C语言版)》电子教案第2章

数据元素,返回一特殊值(例如0),表示查找失败。
(5) 插入元素Inselem (L,i,x) 在线性表L的第 i 个位置上插入一个值为 x 的新元素,这样 使原序号为 i , i+1, ..., n 的数据元素的序号变为 i+1,i+2, ..., n+1,要求1≤i≤Getlen(L)+1,插入后原表长增1。 (6) 删除元素Delelem(L,i) 在线性表L中删除序号为i的数据元素,删除后使序号为 i+1, i+2,..., n 的元素变为序号i, i+1,...,n-1,要求1≤i≤Getlen(L), 删除后表长减1。
typedef int ElemType //在实际应用中,将ElemType定义成实际类型 typedef struct{ ElemType data[MaxLen]; //定义存储表中元素的数组 int length; //线性表的实际长度 }sqList; sqList L; //定义表结构的变量
E in
2012-9-12
i 1
n 1
p i ( n i 1)
1 n 1
i 1
n 1
( n i 1)
n 2
18
由此可以看出,在线性表上做插入操作需要移动表中一 半的数据元素,当n较大时,算法的效率是比较低的,所以 在线性表上进行插入操作的时间复杂度为O(n)。 6.顺序表的删除运算Delelem(L,i)的实现 顺序表的删除运算是指将表中第 i 个元素从线性表中去
i+1。
线性表是一种典型的线性结构。 数据的运算是定义在逻辑结构上的,而运算的具体实现则 是在存储结构上进行的。
2012-9-12
数据结构教案第二章

1、建空表:Initlist (&L);
2、求表长度:Listlength(L):返回L中数据元素个数
3、按序号取值:GetElem(L,i,&e):用 e 返回L中第i数据元素的值
4、按值查找:LocateElem(L,e,compare()) 初始条件:线性表 L 已存在,compare()是数据元素判定函数
课程名称 教材 授课内容
数据结构
教学对象
数据结构(C 语言)
第二章 线性表
新华软工专业
课时
2
教学目的
本章主要介绍线性表的定义、运算和线性表的几种存储结
与要求 构等内容
重点、难点
重点:线性表的定义、线性表的基本操作,线性表的存储结构 难点:线性表的基本操作,线性表的存储结构
课型
电脑+理论
教学方法
投影、讨论、板书
以它的操作与其它位置不同,这将造成同一数据结构上操作的不一致性,不 科学
因此,在表头前一个结点--头结点,使单链表成为带头结点的单链表, 既可解决操作一致性的问题
以后,我们将在该结构上讨论操作 说明:
在单链表中,每一个元素的存储位置都包含在其直接前驱结点的信息之 中
有:P指向 ai 元素 p->next 指向 ai+1 元素
3、线性链表基本操作的算法:(用时 40 分钟)
如何在线性链表的实现基本操作?如何建表?如何插入?删除? 约定带头结点的线性链表存储线性表
1)初始化操作: 功能:建空线性表 参数:head 为线性链表的头指针 主要步聚:调用 malloc()分配一结点的空间,并将其地址赋值给 head
算法: LNode *create-head( ) { LNode *head; head=(Linklist )malloc(sizeof(LNode)); head->next=NULL; Return (head);
数据结构第2章b-12级

第2章 线 性 表
2.3.2 单链表上的基本运算
• 建立
– 头插法: – 尾插法: – 带头结点的尾插法:
• 查找 • 删除运算
第2章 线 性 表
一、建立单链表
尾插法建表 头插法建表 从空表开始 重复读入数据 创建新结点 将新结点插入到链 表的表头上 直到读入结束标志 从空表开始 重复读入数据 创建新结点 将新结点插入到当 前链表的表尾上 直到读入结束标志
第2章 线 性 表
前插操作图示:
原链表序列: a1,a2,……ai-1,ai 插入后链表序列:a1,a2,……ai-1,x,ai
q
head
p ai x
a1 s
ai-1
第2章 线 性 表
前插操作具体算法如下:
void INSERTBEFORE(linklist *head, linklist *p, datatype x) { linklist *s,*q; s=(linklist *)malloc(sizeof(linklist)); s->data=x; q=head; while(q->next!=p)q=q->next; s->next=p; q->next=s; }
第2章 线 性 表
思 考
• (1)观察头指针head的变化 • (2)单链表中每一个新结点的 产生过程是否完全相同 • (3)生成链表中结点的顺序与 输入顺序有什么关系
第2章 线 性 表
第2章 线 性 表
• (1) 头插法建表 从一个空表开始,重复读入数据,生成新结点,将 读入数据存放在新结点的数据域中,然后将新结点插 入到当前链表的表头上,直到读入结束标志为止。
第2章 线 性 表
数据结构课件-第二章

1初始化单链表 Void InitList(LinkList *head) {/* 初始化单链表 */ head=(LinkList)malloc(Sizeof(ListNode)) /*申请头结点空间,并使头指针head指向头结点 */ head->next=NULL; /* 置链尾标记NULL */ }
2.4线性表的链式存储结构
链式存储结构用一组任意的存储单元依次存储 线性表里元素,这组存储单元可以是连续的, 也可以是不连续的,甚至是零散分布在内存的 任何位置上。
为反映出各元素在线性表中的逻辑关系,对每 个数据元素来说,除了存储其本身的信息之外 ,还需存储一个指示其直接后继的信息(即直 接后继的存储位置)。这两部分信息组成一个 数据元素的存储映象,称为结点(Node)。
例如,图2-4-2所示为线性表(dog,pig,cat,fox,hen,bat ,bee,bird)的单链表存储结构,整个链表的存取需从头指针开始 进行,依次顺着每个结点的指针域next找到线性表的各个元素,直 至next域为空为止。
通常我们用箭头表示链域中的指针:
typedef struct Node {ElemType data; /*数据域*/ struct Node *next; /*指针域*/ }ListNode,*LinkList;
2.3.1 线性表的顺序存储
线性表的顺序存储是指用一组地址连续的存储单元依 次存储线性表中的各个元素,使得线性表中在逻辑结 构上相邻的数据元素存储在相邻的存储单元中 。
假设线性表中有n个数据元素,每个数据元素占K个 存储单元,第一个元素a1的存储地址用LOC(a1)表示 ,第i个数据元素ai的地址用LOC(ai)表示,则: 第i个数据元素的地址为: LOC(ai)=LOC(a1)+(i-1)×K (1≤i≤n)
《数据结构(C++版)(第二版)》第02章

2.2.3 顺序表存储空间的动态分配
上面介绍的线性表顺序存储,是预先给定大小为maxsize的存储空间,程序在编译 阶段就会知道该类型变量的大小,在程序开始运行前,就会为它分配好存储空间, 故是一种存储空间的静态分配。而动态分配是在定义线性表的存储类型时,不是定 义好一个数组空间,而是只定义一个指针,待程序运行后再申请一个用于存储线性 表的空间,并把该空间的首地址赋给这个指针。访问动态存储分配的线性表中的元 素和访问静态存储分配的线性表中的元素的情况完全相同,既可以采用指针方式, 也可以采用数组下标方式。 若将前面线性表的顺序存储结构类型中的数组形式改为指针形式,则得到动态分配 形式如下: class sequenlist { public: elemtype *a; int len; …… };
2
2.线性表的特征 从线性表的定义可以看出线性表的特征: (1)有且仅有一个开始结点(表头结点)a1,它没有直接前驱,只有一个直接 后继; (2)有且仅有一个终端结点(表尾结点)an,它没有直接后继,只有一个直接 前驱; (3)其他结点都有一个直接前驱和直接后继; ( 4)元素之间为一对一的线性关系。 因此,线性表是一种典型的线性结构,用二元组表示为: linear_list=(A,R) 其中 A={ai ∣1≤i≤n,n≥0,ai∈elemtype} R={r} r={<ai,ai+1> ∣1≤i≤n-1} 对应的逻辑结构图如下所示。
4
2.1.3 线性表的抽象数据类型描述
上述这些操作可用抽象数据类型描述为: ADT Linearlist is Data: 一个线性表L定义为L=(a1,a2,…,an),当L=()时定义为一个空表。 Operation: void setnull(&L) //将线性表L置成空表 int Length(L) //求给定线性表L的长度 elemtype Get(L,i) //取线性表L第i个位置上的元素 elemtype Prior(L,x) //求线性表L中元素值为x的直接前驱 elemtype Next(L,x) //求线性表L中元素值为x的直接后继 int Locate(L,x) //在线性表L中查找值为x的元素位置 void Insert(&L,x,i) //在线性表L中第i个位置上插入值为x的元素 void Dele(&L,i) //删除线性表L中第i个位置上的元素 END Linearlist
数据结构(第二章)

建立顺序表
void creat_sqlist(Sqlist L) { int i,n; cout<<"n=?; cin>>n; L.length=n; for (i=0; i<n; i++) cin>>L.a[i]; }
initlist(Sl);
输出顺序表
void outputl(Sqlist L) { int i; cout<<"List length" <<L.length<<endl; for (i=0; i<L.length; i++) { cout<<L.a[i]<<" "; if ((i+1)%10==0) cout<<endl; } cout<<endl; }
4. 合并:两表分别非递减有序(递增或等值),合并后 仍然非递减有序。
void merge_list(Sqlist a, Sqlist b, Sqlist &c) { int i,j,k; i=j=k=0; c.length=a.length+b.length; while (i<=a.length-1 && j<=b.length-1) { if (a.a[i]<=b.a[j]) {c.a[k]=a.a[i]; i++; k++;} else {c.a[k]=b.a[j]; j++; k++;} } while (i<=a.length-1) { c.a[k]=a.a[i]; i++; k++; } while (j<=b.length-1) { c.a[k]=b.a[j]; j++; k++; } }
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第二章线性表线性结构特点:•唯一头元素•唯一尾元素•除头元素外,均有一个直接前驱•除尾元素外,均有一个直接后继书目信息、排队、算术表达式。
2.1 线性表的定义1. 线性表的语言定义线性表是n个数据元素的有限序列。
例,英文字母表(A,B,C,……,Z)线性表中的数据元素也可以由若干个数据项构成。
例,包含大量记录的登记表线性表可以表示为n 个数据元素的有限序列: (a1,…,a i-1,a i,…,a n)其中a1是头元素,a n是尾元素,a i是第i 个元素。
a i-1是a i的直接前驱,a i是a i-1的直接后继。
抽象数据类型线性表List 的定义:ADT List {数据对象: D = { a i | a i∈ElemSet,i = 1, 2, …, n }数据关系: R1 = { < a i-1, a i > }基本操作:InitList( &L )结果: 构造一个空的线性表L。
DestroyList( &L )条件: 线性表L 已存在。
…} ADT List其它基本操作包括:ClearList( &L )ListEmpty ( L )ListLength ( L )GetElem ( L,i,&e )LocateElem ( L,e,compare() )PriorElem ( L,cur_e,&pre_e )NextElem ( L,cur_e,&next_e )ListInsert ( &L,i,e )ListDelete ( &L,i,&e )ListTraverse ( L,visit() )2.2 线性表的顺序表示和实现线性表的顺序表示指的是用一组地址连续的存储单元依次存储线性表的数据元素。
线性表顺序存储结构表示# define LIST_INIT_SIZE 100# define LISTINCREMENT 10typedef struct {Elemtype* elem; //数据元素int length; // 表长,初始为0int listsize; // 表存储容量} SqList;Status InitList_Sq ( SqList &L ) { //初始化空线性表L.elem = ( ElemType * ) malloc( LIST_INIT_SIZE * sizeof(ElemType) );if ( ! L.elem ) exit(OVERFLOW) ;L.length = 0 ;L.listsize = LIST_INIT_SIZE ;return OK ;}线性表的顺序存储结构的优点•可随机存取表中任意数据元素(第i 个)L.elem[i-1]* (L.elem+i-1)•直接可获取线性表的长度L.length算法2.4 在第i个数据元素之前插入一个新的元素例,在第i 个元素前插入b思想:1. 找到第i个元素的位置。
2. 将第n到i个元素均向后移动一个位置。
3. 将新元素放置在第i个位置。
int ListInsert_Sq ( Sqlist &L ,int i ,ElemType e ) {ElemType *p, *q;q = & L.elem[i-1] ;//找到第i 个元素位置for ( p = & L.elem[L.length-1] ;p >= q ;p -- )* (p+1) = * p ;// 后移元素* q = e ;// 插入新元素++L.length ;return 0;}int ListDelete_Sq ( Sqlist &L ,int i ,ElemType &e ) {if ( i < 1 || i > L.length ) return 1 ;p = & L.elem[i-1] ;// 找到第i 个元素e= * p ;// 取第i 个元素的值for ( p++ ;p <= & L.elem[ L.length - 1];p ++ )* (p - 1) = * p ;// 前移-- L.length;return 0 ;}2.3 线性表的链式表示和实现线性表的链式存储结构的特点是用一组随意的存储单元存储线性表的数据元素。
例,线性表数据为{3,5,7}结点: 两部分信息组成,存储数据元素信息的数据域,存储直接后继存储位置信息的指针域。
线性表的单链表存储结构typedef struct LNode {ElemType data ;struct LNode * next ;} * LinkList ;2.3.1 线性单链表Head: 头指针,指向链表中第一个结点。
0: 空指针,有时也表示为“NULL”或“∧”。
头结点: 为了某些操作的方便,通常在链表第一个结点之前附加一个结点,没有实际意义。
空表:线性表的链式存储结构的特点缺点:•不可随机存取表中任意数据元素•不可直接获取线性表的长度算法2.8: 取出线性单链表第i个元素。
思想:1. 找到第1 个元素;2. 循环找到第i个元素;3. 取出元素;Status GetElem_L ( LinkList L,int i,ElemType &e ) { p = L->next ;j = 1 ;//p指向第一个元素,j计数while ( p && j < i ) {p = p->next ;++j ;//循环找到第i 个元素}if ( ! p || j > i ) return ERROR ;e = p->data ;return OK ;}例,取出第i=3个元素。
e = p->data = Sun平均时间复杂度: O(n)优点:数据元素的插入、删除相对方便在b之前插入元素x :1. 找到b结点的前驱结点2. 构造将要插入的结点3. 指针变换算法2.9 在第i个数据元素之前插入一个新的元素Status ListInsert_L ( LinkList &L ,int i ,ElemType e ) {1. 找到第i 个结点的前驱结点2. 构造将要插入的结点3. 指针变换}Status ListInsert_L ( LinkList &L ,int i ,ElemType e ) { p = L;j = 0;while ( p && j < i - 1 ) { p = p->next ;++j ;}//找到第i 个结点的前驱结点if ( ! p || j > i - 1 ) return ERROR ;s = ( LinkList ) malloc ( sizeof (LNode) ) ;s->data = e ;s->next = NULL ;//建立新结点s->next = p->next ;p->next = s ;//插入新结点return OK ;}例,在第3个元素之插入一个新元素。
p->next = ss->next = p->next平均时间复杂度: O(n)算法2.11 利用插入操作构造一条完整的单链表。
void CreateList_L ( LinkList &L,int n ) {L = ( LinkList ) malloc ( sizeof (LNode) ) ;L->next = NULL ;//建立头结点for ( i = n ;i > 0 ;--i ) {p = ( LinkList ) malloc ( sizeof (LNode) ) ;Scanf ( &p->data ) ;p->next = L->next ;L->next = p ;//在表头插入新结点}}例,讨论: 如何逆置一个单链表为一个新表?作业: 设计算法,将单链表L 中的第i 个结点和其后继结点交换位置,要求只修改指针。
删除元素b :1. 确定指针2. 取出要删除的结点3. 指针变换4. 释放内存1)p ->next = p ->next ->next2)q = p->nextp->next = q->nextfree(q) ;讨论单链表的删除操作,课堂演讲。
2.3.2 其他线性链表•循环链表•双向链表从某个结点出发寻找直接后继?从某个结点出发寻找直接前驱?1. 循环链表表中最后一个结点的指针域指向头结点,形成一个环。
优点:从表的任意结点出发均可以找到表中的任意其他结点。
空表:操作与线性单链表基本一致,差别只是在于算法中的循环结束条件不是p是否为空,而是p是否等于头指针。
例,取循环链表第i 个元素。
Status GetElem_L ( LinkList L,int i,ElemType &e ) { p = L->next ;j = 1 ;while ( p <> L && j < i ) {p = p->next ;++j ;}if ( p == L || j > i ) return ERROR ;e = p->data ;return OK ;}顺次合并两个线性表有时为了方便某些操作,通常在循环链表中设立尾指针。
Tail2->next = Tail1->nextp = Tail2->next ->nextTail2->next = Tail1->nextTail1->next = pp = Tail2->next ->nextq = Tail2->nextTail2->next = Tail1->nextTail1->next = pFree(q)在循环链表中寻找结点的直接后继很简单,只需要O(1);但要寻找结点的直接前趋需要循环一遍,需要O(n)。
2. 双向循环链表双向循环链表的结点有两个指针域: 一个指向直接后继,一个指向直接前趋。
typedef struct DuLNode{ElemType data ;struct DuLNode * prior ;struct DuLNode * next ;}DuLNode ,* DuLinkList ;空表:性质: 设d 是指向某个结点的指针,则有d->next->prior = d->prior->next = d操作: 插入、删除操作将会处理两个方向。