数据结构 线性表
数据结构第1讲---线性表
34F2 地址 被释放,变 量P与地址 34F2没有关 系
p1^
200 34F2
34F2
new(p1) ——向计算机申请内存地址 p1^:=200 ——给p1指向的单元赋值 dispose(p1) ——释放存储单元
链式结构——什么是指针
Type p=^integer; arr=array[1..4] of char; arrp = ^arr; Var p1:p; p2:arrp;
线性结构 数据的逻辑结构 数 据 结 构 树形结构 图形结构 数据的存储结构 顺序存储
链式存储
数据结构的基本运算 :查找、插入、删除等
三、线性结构——线性表
1、线性表的概念
线性表是由n(n≥0)个具有相同特性数据元素(结点)
a1,a2,…,an组成的有限序列。
线性表的长度:所含元素的个数,用n表示,n>=0。
在我们生活中有哪些属于线性表的例子,列举几个。 1、英文字母表(A,B,…,Z)是线性表, 表中每个字母是一个数据元素(结点)
2、学生成绩表中,每个学生及其成绩是一
个数据元素,其中数据元素由学号、姓名、
各科成绩及平均成绩等数据项组成。
4、线性表的顺序存储
顺序存储是线性表的一种最 简单的存储结构,存储方式是: 在内存中为线性表开辟一块连 续的存储空间。用数组来存放 每一个节点。
[例4-2] 法雷序列
[问题描述]对任意给定的一个自然数n(n<=100),将 分母小于等于n的不可约的真分数按上升次序排序,并 且在第一个分数前加0/1,而在最后一个分数后加1/1, 这个序列称为n级的法雷序列。 当n=8时序列为:0/1, 1/8, 1/7, 1/6,1/5, 1/4,2/7,1/3,3/8, 2/5,3/7,1/2,4/7,3/5,5/8,2/3,5/7,3/4, 4/5,5/6,6/7,7/8, 1/1 。 编程求出n级的法雷序列,每行输出10个分数。
数据结构第二章:线性表
实现:可用C 实现:可用C语言的一维数组实现
6
V数组下标 0 1
内存 a1 a2
元素序号 1 2
typedef int DATATYPE; #define M 1000 DATATYPE data[M]; 例 typedef struct card { int num; char name[20]; char author[10]; char publisher[30]; float price; }DATATYPE; DATATYPE library[M];
4
{加工型操作 加工型操作} 加工型操作
ClearList( &L ) 初始条件:线性表 L 已存在。 操作结果:将 L 重置为空表。 PutElem( &L, i, &e ) 初始条件:线性表L已存在,1≤i≤LengthList(L)。 操作结果:L 中第 i 个元素赋值同 e 的值 ListInsert( &L, i, e ) 初始条件:线性表 L 已存在,1≤i≤LengthList(L)+1。 操作结果:在 L 的第 i 个元素之前插入新的元素 e,L 的长度增1。 ListDelete( &L, i, &e ) 初始条件:线性表 L 已存在且非空,1≤i≤LengthList(L)。 操作结果:删除 L 的第 i 个元素,并用 e 返回其值,L 的长度减1。 }ADT LIST
3
PriorElem( PriorElem L, cur_e, &pre_e ) 初始条件:线性表 L 已存在。 操作结果:若 cur_e 是 L 中的数据元素,则用 pre_e 返回 它的前驱,否则操作失败,pre_e 无定义。 NextElem( NextElem L, cur_e, &next_e ) 初始条件:线性表 L 已存在。 操作结果:若 cur_e 是 L 中的数据元素,则用 next_e 返 回它的后继,否则操作失败,next_e 无定义。 GetElem( GetElem L, i, &e ) 初始条件:线性表 L 已存在,1≤i≤LengthList(L)。 操作结果:用 e 返回 L 中第 i 个元素的值。 LocateElem( LocateElem L, e, compare( ) ) 初始条件:线性表 L 已存在,compare( ) 是元素判定函数。 操作结果:返回 L 中第1个与 e 满足关系 compare( ) 的元 素的位序。若这样的元素不存在,则返回值为0。 ListTraverse(L, visit( )) ListTraverse 初始条件:线性表 L 已存在,visit( ) 为元素的访问函数。 操作结果:依次对 L 的每个元素调用函数 visit( )。 一旦 visit( ) 失败,则操作失败。
【数据结构】线性表的基本操作
【数据结构】线性表的基本操作【数据结构】线性表的基本操作1:定义1.1 线性表的概念1.2 线性表的特点2:基本操作2.1 初始化操作2.1.1 空表的创建2.1.2 非空表的创建2.2 插入操作2.2.1 在指定位置插入元素2.2.2 在表头插入元素2.2.3 在表尾插入元素2.3 删除操作2.3.1 删除指定位置的元素2.3.2 删除表头的元素2.3.3 删除表尾的元素2.4 查找操作2.4.1 按值查找元素2.4.2 按位置查找元素2.5 修改操作2.5.1 修改指定位置的元素 2.5.2 修改指定值的元素3:综合操作3.1 反转线性表3.2 合并两个线性表3.3 排序线性表3.4 删除重复元素3.5 拆分线性表4:线性表的应用场景4.1 数组的应用4.2 链表的应用4.3 栈的应用4.4 队列的应用附件:无法律名词及注释:- 线性表:根据某种规则排列的一组元素的有限序列。
- 初始化操作:创建一个空的线性表,或者创建一个已经包含一定元素的线性表。
- 插入操作:在线性表的指定位置或者表头、表尾插入一个新元素。
- 删除操作:从线性表中删除掉指定位置或者表头、表尾的元素。
- 查找操作:在线性表中按照指定的元素值或者位置查找元素。
- 修改操作:更改线性表中指定位置或者值的元素。
- 反转线性表:将线性表中的元素顺序颠倒。
- 合并线性表:将两个线性表合并成一个新的线性表。
- 排序线性表:按照某种规则对线性表中的元素进行排序。
- 删除重复元素:将线性表中重复的元素删除,只保留一个。
- 拆分线性表:将一个线性表分成多个不重叠的子线性表。
02331自考数据结构 第二章 线性表
return ;
}
if ( L -> length >= ListSize ){
printf (" overflow ");
return ;
}
for ( j - L -> length -1; j >= i -1; j --)
L ->data [ j +1]= L -> data [ j ]; //从最后一个元素开始逐一后移
线性表的基本运算
上述运算仅仅是线性表的基本运算,不是其全部运 算。因为对不同问题的线性表,所需要的运算可能不同。 因此,对于实际问题中涉及其他更为复杂的运算,可用 基本运算的组合来实现。
线性表的基本运算
【例2.1】假设有两个线性表 LA 和 LB 分别表示两个 集合 A 和 B ,现要求一个新集合 A = A∪B 。
线性表的逻辑定义
数据元素“一个接一个的排列”的关系叫做 线性关系,线性关系的特点是“一对一”,在计 算机领域用“线性表”来描述这种关系。另外, 在一个线性表中数据元素的类型是相同的,或者 说线性表是由同一类型的数据元素构成的,如学 生情况信息表是一个线性表,表中数据元素的类 型为学生类型;一个字符串也是一个线性表:表 中数据元素的类型为字符型等等。
,
a2
i
,…,
ai-1
,
a.aii++1.1 , .…,
an
)
an
线性表n的-1逻辑结an构和存储结构都发…生了相应的变化, 与插入运算相反,插…入是向后移动元素,而删除运算则
是向前移M动AX元-1 素,除非i=n 时直接删除终端元素,不需移
动元素。
删除前
删除后
数据结构 线性表
(9) Status NextElem_Sq(SqList L, ElemType cur_e, ElemaType &next_e)
//若cur_e是线性表L的元素且不是最后一个,返回它的后继 { for (i=0; i<L.length-1; i++) if (cur_e==L.elem[i]) { next_e=L.elem[i+1]; return OK; } return ERROR; }//NextElem_Sq O(n)
抽象数据类型 唯 一 数据的逻辑结构 确 操作的定义 定
集合 *
线性表
特殊线性表 扩展线性表
线性结构
树形结构 图形结构
灵 活 数据的存储结构 操作的实现 设 计
顺序存储 链式存储 散列(哈希)存储
数据的基本操作:针对结构、针对元素、针对状态
数据结构---第二章 线性表 1
第二章 线性表
2.1 2.2 2.3 2.4
数据结构---第二章 线性表
9
2.2 线性表的顺序存储结构(顺序表)
起始地址为b、最多可容纳maxlen个元素的线性表
下标 存储地址
0
1
b b+c
b+(i-1)c
a1 a2
ai
c个存储单元
i-1
LOC(ai)=LOC(a1)+(i-1)c LOC(ai)=LOC(ai-1)+c
n-1
b+(n-1)c
n-1
int LocateElem_Sq(SqList L, ElemType e, (7) Status (*compare)(ElemType,ElemType) ) //在线性表L中查找第1个值与e满足 //compare()的元素的位序 { for (i=0; i<L.length; i++) L.elem[i]==e if ( (*compare)(L.elem[i],e) ) return i+1; return 0 ; //作为未找到的特殊标记 } // LocateElem_Sq O(n) P25-2.6
数据结构课件第2章线性表
27
线性表的顺序存储结构适用于数据 元素不经常变动或只需在顺序存取设备 上做成批处理的场合。为了克服线性表 顺序存储结构的缺点,可采用线性表的 链式存储结构。
28
2.3 线性表的链式存储结构
线性表的链式存储表示 基本操作在单链表上的实现 循环链表 双向链表 线性表链式存储结构小结
2.3.1 线性表的链式存储表示 29
2.1.1 线性表的定义
6
一个线性表(linear_list)是 n(n≥0)个具有相同属性的数 据元素的有限序列,其中各元素有着依次相邻的逻辑关系。
线性表中数据元素的个数 n 称为线性表的长度。当 n = 0 时 该线性表称为空表。当 n > 0 时该线性表可以记为:
(a1,a2,a3,…,ai,…,an)
数据域 指针域
结点 data next
31
(2) 线性表的单链表存储结构
通过每个结点的指针域将线性表中 n 个结点按其逻辑顺序链 接在一起的结点序列称为链表,即为线性表 ( a1, a2, a3, …, ai, …, an ) 的链式存储结构。如果线性链表中的每个结点只有一个指针域, 则链表又称为线性链表或单链表 (linked list)。
17
(2) 算法编写
#define OK 1
#define ERROR 0
Int InsList ( SeqList *L, int i, ElemType e ) /*在顺序线性表 L 中第 i 个位置插入新的元素 e。*/ /* i 的合法值为 1≤i ≤L->last+2*/ {
int k; if ( i < 1) ||( i > L->last+2)) /*首先判断插入位置是否合法*/ { printf(“插入位置i值不合法”);
数据结构-线性结构
数据结构-线性结构线性表线性表是最简单最常见的数据结构,属于逻辑结构;线性表有两种实现⽅式(存储⽅式),分别是顺序实现和链接实现;定义:线性表是由n(>=0)个数据元素组成的有限序列,数据元素的个数n定义为表的长度;术语:前驱, 后继, 直接前驱, 直接后继, 长度, 空表案例:线性表⽤L表⽰,⼀个⾮空线性表可记为L = (a1,a2,..an);a1后⾯的称为a1的后继an前⾯的称为an的前驱a1为起始节点,an为终端节点,任意相邻的两个元素,如a1和a2,a1是a2的直接前驱,a2是a1的直接后继;线性表中元素个数即表的长度,此处为n;表中没有任何元素时,称为空表除了⾸节点和尾节点之外,每个节点都有且只有⼀个直接前驱和直接后继,⾸节点没有前驱,尾节点没有后继;节点之间的关系属于⼀对⼀;线性表的基本运算初始化Initiate(L) 建⽴⼀个空表L(),L不包含数据元素求表长度Length(L) 返回线性表的长度取表元素Get(L,i) 返回线性表的第i个元素,i不满⾜1<=i<=Length(L)时,返回特殊值;定位Locate(L,x)查找x在L中的节点序号,若有多个匹配的返回第⼀个,若没有匹配的返回0;插⼊Insert(L,x,i)将x插⼊到L的第i个元素的前⾯(其他元素往后挪),参数i取值范围为1<=i<=Length(L)+1;运算结束后表长度+1;删除Delete(L,i)删除表L中的第i个元素,i有效范围1<=i<=Length(L);操作结束后表长度-1强调:上述的第i个指的是元素的序号从1开始,⽽不是下标从0开始;另外:插⼊操作要保证操作后数据还是⼀个接着⼀个的不能出现空缺;线性表的顺序存储实现线性表是⼀种逻辑结构,可以通过顺序存储结构来实现,即:将表中的节点⼀次存放在计算机内存中⼀组连续的存储单元中,数据元素在线性表中的邻接关系决定了它们在存储空间中的存储位置;换句话说逻辑结构中相邻的两个节点的实际存储位置也相邻;⽤顺序存储结构实现的线性表也称之为为顺序表,⼀般采⽤数组来实现;图⽰:⼤⼩与长度:线性表的⼤⼩:指的是最⼤能存储的元素个数线性表的长度:指的是当前已存储的个数⽰例:c语⾔实现:#include <stdio.h>//初始化操作:const MAX_SIZE = 5;//最⼤长度typedef struct list {int data[MAX_SIZE];//数组int length;//当前数据长度};//获取targert在表中的位置int locate(struct list *l,int target){for (int i = 0;i < l->length;i++){if (target == l->data[i]){return i + 1;}}return 0;}//获取第loc个元素int get(struct list *l,int loc){if (loc < 1 || loc > l->length){printf("error:位置超出范围\n");return -1;}else{return l->data[loc-1];}}//插⼊⼀个元素到第loc个位置上void insert(struct list *l,int data,int location){if (l->length == MAX_SIZE){printf("errolr:表容量已满\n");return;}if (location < 1 || location > l->length+1){printf("error:位置超出范围\n");return;}//⽬标位置后⾯的内容以此往后挪for (int i = l->length; i >= location; i--) {l->data[i] = l->data[i-1];}//在⽬标位置放⼊新的数据l->data[location-1] = data;l->length+=1;//长度加1}//删除第loc个元素,从⽬标位置往后的元素⼀次向前移动void delete(struct list *l,int loc){if (loc < 1|| loc > l->length){printf("error:位置超出范围\n");return;}//⽬标位置及后⾯的所有元素全部向后移动for (;loc < l->length; ++loc) {l->data[loc-1] = l->data[loc];}l->length-=1;}//打印所有元素测试⽤void show(struct list l){for (int i = 0; i < l.length; ++i) {printf("%d\n",l.data[i]);}}//测试int main() {struct list alist = {};insert(&alist,100,alist.length+1);insert(&alist,200,alist.length+1);insert(&alist,300,alist.length+1);insert(&alist,400,alist.length+1);delete(&alist,1);printf("%d\n",alist.length);show(alist);printf("%d\n",get(&alist,4));printf("%d\n", locate(&alist,300));printf("%d\n", get(&alist,1));return 0;}插⼊算法分析:假设线性表中含有n个元素,在插⼊元素时,有n+1个位置可以插⼊,因为要保证数据是连续的每个位置插⼊数据的概率是: 1/(n+1)在i的位置插⼊时,要移动的元素个数为:n - i + 1算法时间复杂度为:O(n)删除算法分析:假设线性表中含有n个元素,在删除元素时,有n个位置可以删除每个位置插⼊数据的概率是: 1/n在i的位置删除时,要移动的元素个数为:n - i算法时间复杂度为:O(n)插⼊与删除的不⾜顺序表在进⾏插⼊和删除操作时,平均要移动⼤约⼀半的数据元素,当存储的数据量⾮常⼤的时候,这⼀点需要特别注意;简单的说,顺序表在插⼊和删除时的效率是不够好的;特别在数据量⼤的情况下;顺序表总结:1.顺序表是⼀维数组实现的线性表2.逻辑上相邻的元素,在存储结构中也是相邻的3.顺序表可实现随机读取优缺点:优点:⽆需为了表⽰元素直接的逻辑关系⽽增加额外的存储空间可⽅便的随机存取表中的任⼀节点缺点:插⼊和删除运算不⽅便,需要移动⼤量的节点顺序表要求占⽤连续的存储空间,必须预先分配内存,因此当表中长度变化较⼤时,难以确定合适的存储空间⼤⼩;顺序表节点存储地址计算:设第i个节点的存储地址为x设顺序表起始地址为loc,每个数据元素占L个存储单位计算公式为:x = loc + L * (i-1)如 loc = 100 i = 5 L = 4 则 x = 116线性表的链接存储实现线性表也可通过链接存储⽅式来实现,⽤链接存储⽅式实现的线性表也称为链表 Link List链式存储结构:1.可⽤任意⼀组存储单元来存储数据2.链表中节点的逻辑次序与物理次序不⼀定相同3.每个节点必须存储其后继节点的地址信息(指针)图⽰:单链表单链表指的是只能沿⼀个⽅向查找数据的链表,如上图每个节点由两个部分(也称为域)组成data域存放节点值得数据域next域存放节点的直接后继的地址的指针域(也称为链域)节点结构:每个节点只知道⾃⼰后⾯⼀个节点却不知道⾃⼰前⾯的节点所以称为单链表图⽰:带有head节点的单链表:单链表的第⼀个节点通常不存储数据,称为头指针,使⽤头指针来存储该节点的地址信息,之所以这么设计是为了⽅便运算;单链表特点:其实节点也称为⾸节点,没有前驱,所以头指针要指向该节点,以保证能够访问到起始节点;头指针可以唯⼀确定⼀个链表,单链表可以使⽤头指针的名称来命名;终端节点也称尾节点,没有后继节点,所以终端节点的next域为NULL;除头结点之外的⼏点称为表结点为⽅便运算,头结点中不存储数据单链表数据结构定义//数据结构定义typedef struct node {struct node *next;int data,length;} Node, *LinkList;/** typedef 是⽤来取别名的* Node 是struct node 的别名* *LinkList 是 struct node *的别名* 后续使⽤就不⽤在写struct关键字了*/运算:初始化⼀个空链表有⼀个头指针和⼀个头结点构成假设已定义指针变量L,使L指向⼀个头结点,并使头结点的next为NULL//时间复杂度 :O(1)LinkList initialLinkList() {// 定义链表的头结点LinkList head;//申请空间head = malloc(sizeof(struct node));//使头结点指向NULLhead->next = NULL;return head;}求表长从头指针开始遍历每个节点知道某个节点next为NULL为⽌,next不为空则个数len+1;//求表长时间复杂度 :O(n)int length(LinkList list){int len = 0;Node *c = list->next;while(c != NULL){len+=1;c = c->next;}return len;}读表元素给定⼀个位置n,获取该位置的节点遍历链表,过程中若某节点next为NULL或已遍历个数index=n则结束循环//从链表中获取第position个位置的节点时间复杂度 :O(n)Node *get(LinkList list, int position) {Node *current;int index = 1;current = list->next;//如果下⾯还有值并且还没有到达指定的位置就继续遍历要和查找元素区别开这就是⼀直往后遍历直到位置匹配就⾏了 while (current != NULL && index < position) {current = current->next;index += 1;}if (index == position) {return current;}return NULL;}定位对给定表元素的值,找出这个元素的位置遍历链表,若某节点数据域与要查找的元素data相等则返回当前遍历的次数index//求表head中第⼀个值等于x的结点的序号(从1开始),若不存在这种结点,返回结果为0 时间复杂度 :O(n)int locate(LinkList list,int data){int index = 1;Node *c;c = list->next;while (c != NULL){if (c->data == data){return index;}index+=1;c = c->next;}return 0;}插⼊在表的第i个数据元素结点之前插⼊⼀个以x为值的新结点new获取第i的节点的直接前驱节点pre(若存在),使new.next = pre.next;pre.next = new;//在表head的第i个数据元素结点之前插⼊⼀个以x为值的新结点时间复杂度 :O(n)void insert(LinkList list, int position, int data) {Node *pre, *new;if (position == 1) {//若插⼊位置为1 则表⽰要插⼊到表的最前⾯即head的后⾯pre = list;} else {//pre表⽰⽬标位置的前⼀个元素所以-1pre = get(list, position - 1);if (pre == NULL) {printf("error:插⼊的位置超出范围");exit(0);}}new = malloc(sizeof(Node));new->data = data;new->next = pre->next;pre->next = new;list->length += 1;}删除删除给定位置的节点获取⽬标节点target的直接前驱节点pre(若pre与⽬标都有效),pre.next = target.next; free(target);//删除链表中第position个位置的节点时间复杂度 :O(n)void delete(LinkList list,int position){//获取要删除节点的直接前驱Node *pre;if (position == 1){ //如要删除的节点是第⼀个那直接前驱就是头结点pre = list;}else{pre = get(list,position-1);}////如果⽬标和前驱都存在则执⾏删除if (pre != NULL && pre->next != NULL){Node *target = pre->next; //要删除的⽬标节点//直接前驱的next指向⽬标的直接后继的nextpre->next = target->next;free(target);printf("info: %d被删除\n",target->data);list->length -= 1;}else{printf("error:删除的位置不正确!");exit(1);}}创建具备指定数据节点的链表//效率⽐较差算法时间复杂度 :O(n^2)LinkList createLinkList1(){LinkList list = initialLinkList();int a;//输⼊的数据int index = 1; //记录当前位置scanf("%d",&a);while (a != -1){ // O(n)insert(list,index++,a); // O(n^2) 每次都要从头遍历链表scanf("%d",&a);}return list;}//尾插算法记录尾节点从⽽避免遍历时间复杂度 :O(n)LinkList createLinkList2(){LinkList list = initialLinkList();int a;//输⼊的数据Node *tail = list;//当前的尾部节点scanf("%d",&a);while (a != -1){ // O(n)Node * newNode = malloc(sizeof(Node)); //新节点newNode->next = NULL;newNode->data = a;tail->next = newNode;//尾部节点的next指向新节点tail = newNode;//新节点作为尾部节点scanf("%d",&a);}return list;}//头插算法每次插到head的后⾯,不⽤遍历但是顺序与插⼊时相反时间复杂度 :O(n)LinkList createLinkList3(){LinkList list = initialLinkList();int a;//输⼊的数据Node * head = list;scanf("%d",&a);while (a != -1){ // O(n)Node * newNode = malloc(sizeof(Node)); //新节点newNode->next = NULL;newNode->data = a;newNode->next = head->next;//将原本head的next 交给新节点;head->next = newNode;//在把新节点作为head的next;scanf("%d",&a);}return list;}优缺点优点:在⾮终端节点插⼊删除时⽆需移动其他元素⽆需预分配空间,⼤⼩没有限制(内存够的情况)缺点:⽆法随机存取读取数据慢链表与顺序表的对⽐:操作顺序表链表读表元O(1)O(n)定位O(n)O(n)插⼊O(n)O(n)删除O(n)O(n)。
数据结构线性表ppt课件
01
02
03
04
插入操作
在链表的指定位置插入一个新 节点,需要修改相邻节点的指
针。
删除操作
删除链表的指定节点,需要修 改相邻节点的指针。
查找操作
从链表的头节点开始,顺序遍 历链表,直到找到目标元素或
遍历到链表末尾。
遍历操作
从链表的头节点开始,顺序访 问每个节点,直到遍历到链表
末尾。
04 线性表应用举例 与问题分析
多项式表示与计算问题
01
02
03
多项式表示方法
数组表示法和链表表示法 。
数组表示法
将多项式的系数按次序存 放在一个数组中,通过下 标表示对应的幂次。
链表表示法
每个节点包含系数和指数 两个数据域,以及一个指 向下一个节点的指针域。
一元多项式相加算法设计
• 算法思想:将两个多项式中的同类项系数相加,得到新的 多项式。
删除操作
删除指定位置i的元素,需要将i之后的元素都向前移动 一个位置。
03 链式存储结构及 其实现
链式存储结构原理及特点
链式存储结构原理
使用一组任意的存储单元存储线 性表的数据元素(这组存储单元 可以是连续的,也可以是不连续 的)。
链式存储结构特点
逻辑上相邻的元素在物理位置上 不一定相邻,元素之间的逻辑关 系是通过指针链接来表示的。
...,an组成的有序序列。
性质
集合中必存在唯一的一个“第一元素 ”。
集合中必存在唯一的一个“最后元素 ”。
除最后元素之外,均有唯一的后继。
除第一元素之外,均有唯一的前驱。
线性表与数组关系
数组是线性表的一种表现和实现形式。
线性表更侧重于逻辑概念,而数组则是这种逻辑概念在计算机中的一种存储方式。
数据结构之线性表
线性表是最简单、最基本、最常用的数据结构。线性表是线性结构的抽象(Abstract),线性 结构的特点是结构中的数据元素之间存在一对一的线性关系。这种一对一的关系指的是数据 元素之间的位置关系,即:( 1)除第一个位置的数据元素外,其它数据元素位置的前面都 只有一个数据元素;( 2)除最后一个位置的数据元素外,其它数据元素位置的后面都只有 一个元素。也就是说,数据元素是一个接一个的排列。因此,可以把线性表想象为一种数据 元素序列的数据结构。
单链表的存储
链表是用一组任意的存储单元来存储线性表中的数据元素(这组存储单元可以是连续的,也 可以是不连续的)。那么,怎么表示两个数据元素逻辑上的相邻关系呢?即如何表示数据元 素之间的线性关系呢?为此,在存储数据元素时,除了存储数据元素本身的信息外,还要存 储与它相邻的数据元素的存储地址信息。这两部分信息组成该数据元素的存储映像(Image), 称为结点(Node)。把存储据元素本身信息的域叫结点的数据域(Data Domain),把存储与它 相邻的数据元素的存储地址信息的域叫结点的引用域(Reference Domain)。因此,线性表 通过每个结点的引用域形成了一根“链条”,这就是“链表”名称的由来。 如果结点的引用域只存储该结点直接后继结点的存储地址,则该链表叫单链表(Singly Linked List)。把该引用域叫 next。单链表结点的结构如图所示,图中 data 表示结点的数 据域。
data = val; next = p; }
//构造器
public DbNode(DbNode<T> p) {
next = p; }
//构造器 public DbNode(T val) { data = val; next = null; }
数据结构线性表
数据结构---线性表线性表代码主要参考严蔚敏《数据结构(c语言版)》,有部分改动线性表的定义定义•线性表是具有相同的数据类型的n(n >= 0)个数据元素的有限序列,当n=0时线性表为一个空表•用L表示线性表则L = (a1,a2,a3,…,ano a1为表头元素,an为表尾元素o a1无直接前驱,an无直接后继特点•表中元素个数有限•表中元素具有逻辑上的顺序,表中元素有先后次序•表中元素都是数据元素•表中元素的数据类型都相同,每个元素占的空间大小一致要点数据项、数据元素、线性表的关系线性表由若干个数据元素组成,而数据元素又由若干个数据项组成,数据项是数据的不可分割的最小单位。
其中姓名,学号等就是数据项线性表的顺序表示顺序表的定义顺序表是指用一组地址连续的存储单元依次存储信息表中的数据元素,从而使得逻辑相邻的两个元素在物理位置上也相邻预先定义(为了代码可以运行)#define True 1#define False 0#define OK 1#define ERROR 0#define INFEASIBLE -1#define OVERFLOW -2typedef int Status;第n个元素的内存地址表示为LOC(A) + (n-1)*sizeof(ElemType)假定线性表的元素类型为ElemType,则线性表的顺序存储类型描述为typedef int ElemType ;#define MaxSize 50typedef struct{ElemType data[MaxSize];int length;}SqList;一维数组可以是静态分配的,也可以是动态分配的。
静态分配后大小和空间都固定了,下面使用动态分配的形式typedef int ElemType ;#define InitSize 100 //表长度的初始大小定义#define ListIncreasement 10 //线性表存储空间的分配增量typedef struct{ElemType *data;int MaxSize,length;}SeqList;顺序表的初始化顺序表的初始化,&是C++的引用,可以使用指针代替Status InitList(SeqList &L){L.data = (ElemType *) malloc(InitSize * sizeof(ElemType));if(! L.data) exit(OVERFLOW);//存储分配失败L.length = 0;L.MaxSize = InitSize;return OK;}顺序表的插入在顺序表L的第i(1<= i <= L.length +1)个位置插入新元素e,需要将第n 个至第i (共n-i+1)个元素向后移动一个位置【最后一个到倒数第n-i+i个元素向后移动一位】。
数据结构导论 第2章 线性表
线性表是一种线性结构,线性结构的特点是数据元 素之间是一种线性关系,数据元素“一个接一个的 排列”。 线性结构是n(n>=0)个结点的有穷序列。对于 n>0的线性结构表示成: (a1,a2,… ai-1,ai,ai+1,…an) a1称为起始结点 an称为终端结点 起始结点, 终端结点; 起始结点 终端结点 ai-1 称为 ai 的直接前趋 i+1 称为 ai 的直接后继 直接前趋,a 直接后继。 直接前趋 直接后继
4.查找(定位) locate(L,x): .查找(定位) :
依次将顺序表L中的每个元素与给定的值x进行比 较。若找到则返回其序号(下标+1),否则返回0。 int locate (sqlist L, datatype x) { int i; for ( i=0; i<st; i++) if (L.data[i]==x) return (i+1); return(0); }
void insert (sqlist *L, datatype x, int i ) { if (i<1 || i>L->last+1) error (“插入位置错误”); else if (L->last==maxsize) error (“溢出”); else { for (j=L->last-1; j>=i-1; j--) //往后移动元素 //往后移动元素 L->data[j+1]=L->data[j]; L->data[i-1]=x; //插入x L->last++; //修改表长 } }
常见的线性表的基本运算有以下几个: 常见的线性表的基本运算有以下几个:
数据结构之线性表详细解答
二章线性表线性表是最简单、最基本、也是最常用的一种线性结构。
它有两种存储方法:顺序存储和链式存储,它的主要基本操作是插入、删除和检索等。
2.1 线性表的逻辑结构2.1.1 线性表的定义线性表是一种线性结构。
线性结构的特点是数据元素之间是一种线性关系,数据元素“一个接一个的排列”。
在一个线性表中数据元素的类型是相同的,或者说线性表是由同一类型的数据元素构成的线性结构。
在实际问题中线性表的例子是很多的,如学生情况信息表是一个线性表:表中数据元素的类型为学生类型; 一个字符串也是一个线性表:表中数据元素的类型为字符型,等等。
综上所述,线性表定义如下:线性表是具有相同数据类型的n(n>=0)个数据元素的有限序列,通常记为:(a1,a2,… a i-1,a i,a i+1,…a n)其中n为表长,n=0 时称为空表。
表中相邻元素之间存在着顺序关系。
将a i-1 称为a i 的直接前趋,a i+1 称为a i 的直接后继。
就是说:对于a i,当i=2,...,n 时,有且仅有一个直接前趋a i-1.,当i=1,2,...,n-1 时,有且仅有一个直接后继a i+1,而a1 是表中第一个元素,它没有前趋,a n 是最后一个元素无后继。
需要说明的是:a i为序号为i 的数据元素(i=1,2,…,n),通常我们将它的数据类型抽象为datatype,datatype根据具体问题而定,如在学生情况信息表中,它是用户自定义的学生类型; 在字符串中,它是字符型; 等等。
2.1.2 线性表的基本操作在第一章中提到,数据结构的运算是定义在逻辑结构层次上的,而运算的具体实现是建立在存储结构上的,因此下面定义的线性表的基本运算作为逻辑结构的一部分,每一个操作的具体实现只有在确定了线性表的存储结构之后才能完成。
线性表上的基本操作有:⑴线性表初始化:Init_List(L)初始条件:表L不存在操作结果:构造一个空的线性表⑵求线性表的长度:Length_List(L)初始条件:表L存在操作结果:返回线性表中的所含元素的个数⑶取表元:Get_List(L,i)初始条件:表L存在且1<=i<=Length_List(L)操作结果:返回线性表L中的第i个元素的值或地址⑷按值查找:Locate_List(L,x),x是给定的一个数据元素。
数据结构 第二章__线性表(本)
数据结构与算法华东师范大学计算机系杨沛第二章线性表2.1 线性表的基本概念线性表是具有相同数据类型的数据元素的有限序列。
由n(n≥0)个数据元素k0,k1,…,kn-1组成的线性表记为(k0 ,k1 ,…,kn-1),线性表中包含的数据元素的个数n称为线性表的长度(length),称长度为零的线性表为空的线性表(简称为空表)。
相关概念:表头、表尾、前驱、后继有序线性表:数据元素的相对位置与它们的值有联系。
无序线性表:数据元素的相对位置与它们的值没有联系。
第二章线性表例小于20的质数组成的线性表(2,3,5,7,11,13, 17,19);英文字母表也是线性表,表中每个字母是一个数据元素:(A,B,C,……,Z);2.2 顺序表2.2.1 线性表顺序表(sequential list)就是顺序存贮的线性表,即用一组连续的存贮单元依次、连续地存贮线性表中的结点。
如果每个结点占用s个存贮单元,并假设存放结点ki(0≤i≤n-1)的开始地址为loc(k0),则结点ki的地址loc(ki)可表示成Loc(ki) =loc(k0) + i*s。
2.2 顺序表在C 语言中,可用数组表示线性表:#define MAXN 100int list[MAXN];int n;线性表的结点k 0,k 1,…,k n-1依次存放在数组单元list[0],list[1],…,list[n-1]。
2.2.1 线性表最大表长实际表长线性表2.2 顺序表2.2.1 线性表假设s=sizeof(int),则可得到计算ki的地址的公式,因loc(ki)=&list[i],而&list[i]=&list[0]+i·s,故loc(ki)=&list[0]+i·s。
2.2 顺序表2.2.2 顺序表的操作(1)初始化:初始长度置为0即可(n=0;),数组空间在编译时分配。
(2)顺序表的插入:插入算法的C函数SqListInsert():若插入位置i不在可以插入的位置上,即i<0或i>n,则返回0;若n=MAXN,即线性表已满,此时数组list[]没有多余的存贮单元可以存放新结点,则返回-1;若插入成功,则返回12.2 顺序表实际表长(2)顺序表的插入:int SqListInsert(int list[],int*p_n,int i,int x) {int j;if(i<0||i>*p_n)return(0);//i不是合法的插入位置if(*p_len==MAXN)return(-1);//线性表已满2.2 顺序表for(j=*p_n;j>i;j--)list[j]=list[j-1];//结点右移list[i]=x;(*p_n)++;//表长加1return(1);}2.2 顺序表(2)顺序表的插入:对于存放在数组list[]中的、具有n个结点的顺序表,为了把值为x的结点插在表的位置i(0≤i≤n)上,可调用如下的语句:k=SqListInsert(list, &n, i, x);注:结点移动是本算法的关键操作2.2 顺序表(3)顺序表的删除:删除算法的C函数SqListDelete():在具有n个结点的顺序表中,删除第i(0≤i≤n-1)个位置上的结点,使线性表长度减1,若删除位置不合法,即i<0或i≥n,则返回0;若删除位置合法,即0≤i≤n-1,则删除成功,返回1。
数据结构——线性表(顺序实现)
数据结构——线性表(顺序实现) 好好学习基础知识,出⼈头地就靠它了,内外兼修。
(好吧,我现在内外都不⾏)写这篇⽂章的⽬的就是为了,巩固刚学完的线性表,个⼈能⼒有限,若有不当之处,望指出。
线性表 好了,扯完了,说正事: 1、定义 线性表是⼀种及其常⽤的并且最简单的⼀种数据结构。
简单来说,线性表就是集合⾥的元素的有限排列。
(在这⾥我把集合定义为具有相同属性的元素,会有些狭义) 在线性表中数据元素之间的关系是⼀对⼀的关系,即除了第⼀个和最后⼀个数据元素之外,其它数据元素都是⾸尾相接的(注意,这句话只适⽤⼤部分线性表,⽽不是全部。
⽐如,循环链表逻辑层次上也是⼀种线性表(存储层次上属于链式存储),但是把最后⼀个数据元素的尾指针指向了⾸位结点)[] 怎么说呢,毕竟数据结构毕竟是逻辑结构,逻辑上符合线性结构的特征即可,存储结构能实现就⾏。
线性表的很重要!很重要!很重要!后⾯的栈,队列,串等都是基于线性表的基础上实现的,所以说⼀定要学好线性表 2、线性表的特点: 对于任意的的⾮空线性表或者线性结构有: 1、存在唯⼀⼀个被称为 ”第⼀个“的元素 2、存在唯⼀⼀个被称为 ”最后⼀个“的元素 3、出第⼀个元素之外,每⼀个元素都存在⼀个后继 4、除最后⼀个元素之外,每⼀个元素都存在⼀个前驱 3、基本操作 1、Create(*L)创建空表 2、InitEmpty(*L)初始化 3、getLength(*L)获取长度 4、Insert(*L)插⼊元素 5、Remove(*L)移除元素 6、IsEmpty(*L)空表检测 7、IsFulled(*L)表满检测(顺序表常⽤,链式表基本不⽤) 8、Delete(*L)删除表 9、getElemt(*L)获取元素 10、Traverse(*L)遍历输出所有元素 11、Clear(*L)清除所有元素 4 、实现 好了最⿇烦的事情开始了,数据结构在计算机上的的映射。
众所周知,线性表有两种实现⽅法,⼀种是顺序表,另⼀种是链式表,这两种结构实现最⼤的不同在于前者逻辑关系⽆需存储空间,⽽后者则需要⽤额外的空间(顺便记录⼀下,指针⼤⼩只由环境有关(严格意义上说和CPU的位数有关)本篇只实现顺序结构)。
第12章-线性表
第12章线性表数据结构: 是相互之间存在一种或多种特定关系的数据元素的集合。
在任何问题中, 数据元素都不是独立存在的, 而是在它们之间存在着某种关系, 这种数据元素相互之间的关系称为结构。
通常有4种结构:(1)集合:结构中的数据元素之间除了“同属于一个集合”的关系外, 别无其它的关系;一个大学同学之间的关系就是“集合”;(2)线性结构: 结构中的数据元素之间存在着一个对一个的关系;一个班级同学之间的学号有先后关系(一对一的关系);(3)树形结构: 结构中的数据元素之间存在一个对多个的关系;一个班主任对该班上的学生之间的关系;(4)图状结构或网状结构: 结构中的数据元素之间存在多个对多个的关系;一个班上的同学之间的关系。
线性结构的特点是:在数据元素的非空有限集中, 存在着以下:(1)存在唯一的一个被称做“第一个”的数据元素(2)存在唯一的一个被称做“最后一个”的数据元素(3)除第一个之外, 集合中的每个数据元素均只有一个前驱(4)除最后一个之外, 集合中的每个数据元素均只有一个后继满足这种关系的数据集合就是“线性表”。
12.1 线性表的定义线性表(Linear List)是最常用且最简单的一种数据结构。
简言之, 一个线性表是n个数据元素的有限序列。
每个数据元素的具体含义可以不同。
在稍复杂的线性表中, 一个数据元素可以由若干个数据项组成(如一个结构体就是一个数据元素, 而结构中的每个成员就是一个数据项)。
在这种情况下, 常把数据元素称为记录, 含有大量记录的线性表又称为文件。
线性表可以有两种实现方式: 顺序方式、链式方式。
顺序方式实现的称为“顺序表”, 链式方式实现的称为“链表”。
12.2 线性表的顺序表示和实现一般表示顺序表的结构为:#define LIST_INIT_SIZE 100 //线性表存储空间的初始分配量#define LISTINCREMENT 10 //线性表存储空间的分配增量typedef int ElemType; //使用typedef定义一种新类型ElemType, 此处它其实就是inttypedef struct{ElemType *elem; //存储空间基址int length; //当前长度int listsize; //当前分配的存储空间(个)}SqList;需要实现的操作有:(1)初始化(2)销毁(3)清空(4)判空(5)求长度(6)获取第i个元素(7)对第i个元素设值(8)在第i个位置上插入一个元素(9)删除第i个元素(10)求某个元素的前驱(11)求某个元素的后继(12)查找某个指定值的元素的位置(13)遍历实现如下:1.初始化/*函数: 初始化一个线性表*/Status InitList_Sq(SqList &L){L.elem=(ElemType*)malloc(sizeof(SqList)*LIST_INIT_SIZE);if(L.elem==NULL) //申请空间失败, 程序直接退出exit(OVERFLOW);L.length=0;L.listsize=LIST_INIT_SIZE;return OK;}其中exit(代码)是直接退出程序。
数据结构(第二章 线性表)
2.2 线性表的顺序存储和实现
顺序表-顺序表定义
由上可知,数据的存储逻辑位置由数组的下标决定。 所以相邻的元素之间地址的计算公式为(假设每个数 据元素占有d个存储单元): LOC(ai)=LOC(ai-1)+d 对线性表的所有数据元素,假设已知第一个数据元 素a0的地址为LOC(a0) ,每个结点占有d个存储 单元, 则第i个数据元素ai的地址为: LOC(ai)=LOC(a0)+i*d 线性表的第一个数据元素的位置通常称做起始位置 或基地址。 在使用一维数组时,数组的下标起始位置根据给定 的问题确定,或者根据实际的高级语言的规定确定。
2.1 线性表抽象数据类型
线性表的分类
顺序存储结构 (元素连续存储、 随机存取结构) 线性表 ADT 链式存储结构 (元素分散存储) 继承 顺序表类 排序顺序表类 继承 单链表类 循环单链表 双链表 继承 排序循环双链表类 排序单链表类
单链表
双链表
循环双链表类
线性表的存储结构
2.2 线性表的顺序存储和实现
线性表的基本操作 求长度:求线性表的数据元素个数。 访问:对线性表中指定位置的数据元素进行存取、替 换等操作。 插入:在线性表指定位置上,插入一个新的数据元素, 插入后仍为一个线性表。 删除:删除线性表指定位置的数据元素,同时保证更 改后的线性表仍然具有线性表的连续性。 复制:重新复制一个线性表。 合并:将两个或两个以上的线性表合并起来,形成一 个新的线性表。 查找:在线性表中查找满足某种条件的数据元素。 排序:对线性表中的数据元素按关键字值,以递增或 递减的次序进行排列。 遍历:按次序访问线性表中的所有数据元素,并且每 个数据元素恰好访问一次。
线性表结构
线性表结构线性表是计算机科学中一种常见的数据结构,它具有容易理解、实现简单及操作性能良好的特点,因而在计算机应用中得到了广泛的使用。
本文将介绍线性表结构的定义、结构特点、相关操作以及实际应用。
一、线性表的定义一个线性表(Linear Table)是一种抽象的数据结构,它由n(n>0)个相同类型的数据元素(成员)组成,其中每个数据元素有且仅有一个直接前驱和一个直接后继,表中最前面一个元素称为头元素,最后一个元素称为尾元素。
二、线性表的特点线性表是一种基本的数据结构,它具备以下几个基本特点:(1)表中元素有顺序关系,元素之间的次序由它们在表中出现的次序决定。
(2)线性表中的每个元素都有且仅有一个直接前驱和一个直接后继,表中的第一个元素没有前驱,表中的最后一个元素没有后继。
(3)线性表中的每个元素都属于相同的数据类型。
(4)线性表是限定性结构,它只能完成表中元素的顺序存取,不能完成元素的随机存取。
三、线性表的应用(1)线性表可以用来存储和操作顺序序列的数据,如求积分、求傅立叶变换等;(2)线性表可用于处理姓名、课程名称、学号等顺序性的数据;(3)线性表可以用于求解算法中的搜索、排序等问题,如快速排序,归并排序等。
四、线性表的操作线性表的操作要求在不改变原表结构的情况下对原表中数据进行插入、删除、更改、查找等操作,常用的操作有:(1)求长度:求表的长度即求表中元素的个数;(2)求特定元素:查找表中某一特定元素;(3)插入元素:向表中插入新的元素;(4)删除元素:删除表中指定位置的元素;(5)拼接表:将两个不同的表拼接成一个表;(6)按序访问:按照表元素在表中出现的次序进行操作。
五、线性表的实际应用线性表在实际应用中被广泛使用,下面简单介绍几个常见的应用场景:(1)链表是重要的动态存储结构,可以用其实现稀疏矩阵的存储;(2)在关系数据库中,用户可以使用线性表来表示关系表本身;(3)操作系统中,可以使用线性表来存储进程调度表、用户登录信息表等;(4)线性表还可以用于各种算法的求解,比如排序算法和回溯法等。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第1讲线性表本章主要掌握如下内容:线性表的定义和基本操作,线性表的实现,线性表的顺序存储结构及链式存储结构,线性表的应用。
知识点分析(一)线性表的定义和基本操作1.线性表基本概念1)定义:是由相同类型的结点组成的有限序列。
如:由n个结点组成的线性表(a1, a2, …, a n)a1是最前结点,a n是最后结点。
结点也称为数据元素或者记录。
2)线性表的长度:线性表中结点的个数称为其长度。
长度为0的线性表称为空表。
3)结点之间的关系:设线性表记为(a1,a2,…a i-1 , a i, a i+1 ,…a n),称a i-1是a i的直接前驱结点....(简称前驱),a i+1是a i的直接后继结点....(简称后继)。
4)线性表的性质:①线性表结点间的相对位置是固定..的,结点间的关系由结点在表中的位置确定。
②如果两个线性表有相同的数据结点,但它们的结点顺序不一致,该两个线性表也是不相等的。
注意:线性表中结点的类型可以是任何数据(包括简单类型和复杂类型),即结点可以有多个成分,其中能唯一标识表元的成分称为关键字(key),或简称键。
以后的讨论都只考虑键,而忽略其它成分,这样有利于把握主要问题,便于理解。
『经典例题解析』线性表的特点是每个元素都有一个前驱和一个后继。
( )【答案】错误。
【解析】线性表的第一个数据元素没有前驱,最后一个元素没有后继。
其余的所有元素都有一个前驱和后继。
2.线性表的抽象数据类型线性表是一个相当灵活的数据结构,其长度可以根据需要增加或减少。
从操作上讲,用户不仅可以对线性表的数据元素进行访问操作,还可以进行插入、删除、定位等操作。
1)线性表的基本操作假设线性表L有数据对象 D={ai | ai∈ElemSet,i=1,2,3,…,n,n>=0},数据元素之间的关系R={<ai-1,ai>|ai-1,ai∈D,i=1,2,…,n},则线性表L的基本操作如下所示:●InitList(&L):其作用是构造一个长度为0的线性表(空线性表);●DestoryList(&L):其作用是销毁当前的线性表L;●ClearList(&L):清空线性表L,使之成为空表;●ListLength(L):返回线性表L的长度,即线性表中数据元素的个数;●ListEmpty(L) :判断线性表L是否为空表,是则返回True,否则返回False;●GetElem(L,i,&e):将线性表L中第i个数据元素的值返回到变量e中;●LocateELem(L,e,compare( )) :判断线性表L中是否存在与e满足compare()条件的数据元素,有则返回第一个数据元素;●PriorElem(L,cur_e,&pri_e):返回线性表L中数据元素cur_e的前驱结点;●NextElem(L,cur_e,&next_e):返回线性表L中数据元素cur_e的后继结点;●ListInsert(&L,i,e):向线性表L的第i个位置之前插入一个数据元素,其值为e;●ListDelete(&L,i,&e):删除线性表L的第i个数据元素,并将该数据元素的值返回到e中;●ListTraverse(L,visit()):遍历线性表中的每个数据元素。
2)线性表的操作举例①用两个线性表La,Lb分别表示两个集合A、B,现要求两个集合的合集,使得A=AUB。
操作如下:依次取出Lb中的元素,然后到La中去找,如果找不到,则将该元素加入La中,同时修改La的长度,如果Lb中的元素同La中的元素相同,那么按照集合的概念,不再加入到La中。
算法描述为:V oid union(List &La , List Lb){ La_len = length(La) ; Lb_len=length(Lb) ;for (i = 1 ; i <= Lb_len ; i++){ GetElem(Lb,i,e) ; //取出Lb的第i个元素,并将之赋值给eif (!LocateElem(La,e,equal))ListInsert(La,++La_len ,e) ;}}②有序线性表合并问题:利用抽象数据类型实现两个线性表的合并已知线性表La和Lb中的数据元素按照非递减有序排列,现在要求La和Lb归并为一个新的有序线性表Lc,使得Lc仍然是非递减有序排列。
思想如下:先设Lc为空表,从La、Lb的开头开始,比较La、Lb当前两个元素的大小,将较小者插入到Lc中。
为了比较方便,我们辅设两个指针i和j,让它们分别指向La和Lb即将参与比较的元素。
将较小元素插入Lc后,该较小元素所在的线性表上辅设的指针向后移动一个位置(+1),另一个指针不变,继续参与下一轮比较,这样一直比到某一个线性表结束(i>La_length || j>Lb_length)。
最后再将还没有比较完的线性表中剩余的元素全部插入Lc中即可。
算法如下:void MergeList(List La , List Lb , List &Lc){InitList(Lc) ;i=j=1 ; //两个指针初始化,i指向La的第一个元素,j指向Lb的第一个元素k=0 ;//用于存储Lc当前元素个数,初始为0La_Length = length(La) ; Lb_Length= length(Lb);while (i<=La_Length && j<= Lb_Length){GetElem(La,i,ai) ;GetElem(Lb,j,bj);if (ai<=bj){ ListInsert(Lc,++k ,ai) ;i++ ;}else{ ListInsert(Lc,++k,bj) ;j++;}} //while//将La或Lb中剩余所有元素全部插入Lc中,以下两句只可能执行一句。
while (i<=La_len){ GetElem(La,i++ ,ai) ; ListInsert(Lc,++k,ai) };While (j<= Lb_len){ GetElem(Lb,j++ , bj)} ; ListInsert(Lc,++k ,bj) );}『经典例题解析』假设有两个按元素值递增次序排列的线性表,均以单链表形式存储。
请编写算法将这两个单链表归并为一个按元素值递减次序排列的单链表,并要求利用原来两个单链表的结点存放归并后的单链表。
【解析】因为两链表已按元素值递增次序排列,将其合并时,均从第一个结点起进行比较,将小的链入链表中,同时后移链表工作指针。
该问题要求结果链表按元素值递减次序排列。
故在合并的同时,将链表结点逆置。
LinkedList Union(LinkedList la,lb)∥la,lb分别是带头结点的两个单链表的头指针,链表中的元素值按递增序排列,本算法将两链表合并成一个按元素值递减次序排列的单链表。
{ pa=la->next; pb=lb->next;∥pa,pb分别是链表la和lb的工作指针la->next=null; ∥la作结果链表的头指针,先将结果链表初始化为空。
while(pa!=null && pb!=null) ∥当两链表均不为空时作{ if(pa->data<=pb->data){ r=pa->next; ∥将pa 的后继结点暂存于r。
pa->next=la->next; ∥将pa结点链于结果表中,同时逆置。
la->next=pa;pa=r; ∥恢复pa为当前待比较结点。
}else{ r=pb->next;∥将pb 的后继结点暂存于r。
pb->next=la->next; ∥将pb结点链于结果表中,同时逆置。
la->next=pb;pb=r; ∥恢复pb为当前待比较结点。
}}while(pa!=null) ∥将la或lb表的剩余部分链入结果表,并逆置。
{r=pa->next; pa->next=la->next; la->next=pa; pa=r; }while(pb!=null){r=pb->next; pb->next=la->next; la->next=pb; pb=r; }}∥算法Union结束。
[算法讨论]上面两链表均不为空的表达式也可简写为while(pa&&pb),两递增有序表合并成递减有序表时,上述算法是边合并边逆置。
也可先合并完,再作链表逆置。
后者不如前者优化。
算法中最后两个while 语句,不可能执行两个,只能二者取一,即哪个表尚未到尾,就将其逆置到结果表中,即将剩余结点依次前插到结果表的头结点后面。
(二)线性表的实现1.顺序存储结构线性表有两种存储方式:顺序存储和链式存储。
顺序存储利用大数组或分配了连续内存空间的指针实现,链式存储利用链表实现。
1) 存储方法:利用一个足够大的数组,从第一个元素开始将线性表的结点依次存储在数组中。
我们知道,数组是顺序存储的,利用数组的目的是用数组的顺序存储来体现线性表中结点的先后次序。
由此得到的线性表称为顺序表,具有“随机存取....”的特点。
2) 地址表示及计算:线性表的顺序存储指的是用一组地址连续的存储单元依次存储线性表的数据元素。
设每个元素占用L个存储单元,并以所占的第一个单元的存储地址作为数据元素的存储位置,则第i+1个元素的存储位置LOC(ai+1)和第i个元素的存储位置LOC(ai)有如下关系:LOC(ai+1)= LOC(ai) +L假设LOC(a1)是线性表第一个数据元素a1的存储位置(线性表的起始位置),则数据元素ai的地址计算公式为:LOC(ai )= LOC(a1) +(i-1)×L假设m>n,则有:LOC(am )= LOC(an) +(m-n)×L3) 线性表的顺序存储结构定义:#define List_INIT_SIZE 100 //初始分配量# define LISTINCREMENT 10 //分配增量typedef struct{ ElemType *elem ; //带有连续地址块的指针变量,相当于一维数组(向量)int length ;//x线性表的当前长度,即当前数据元素的个数,初始值为0int ListSize ; //线性表当前分配的存储容量(以sizeof(ElemType)为单位)}SqList ;线性表初始化时,利用下面的语句为指针成员elem分配连续地址空间:L.elem =(ElemType *)malloc......(LIST_INIT_SIZE *sizeof(ElemType)) ;4) 顺序表的各种操作①初始化线性表Status Init_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 ;}重要说明:●elem为指针变量。