第二章 线性表 1 线性表的逻辑结构及其基本操作 2 线性表的顺序存储结构 3 线性表的链式存储结构 4 静态链表 5 应用实例.

Slides:



Advertisements
Similar presentations
电子成绩单项目实现.
Advertisements

数据结构概论 第2章 线性表 董黎刚 浙江工商大学信电学院
第三章 鏈結串列 Linked List.
第九章 排序 插入排序 交换排序 选择排序 归并排序 基数排序.
引入树 线性表、堆栈和队列都是线性结构,它们的共同特点:一对一; 计算机对弈中的一个格局可能有多个后继格局,用线性结构难以描述。
数据结构算法 模拟练习及解答二 绍兴文理学院 计算机系计算机应用教研室.
第二章 线性表.
第2章 线性表 2.1 线性表的概念及运算 2.2 线性表的顺序存储 2.3 线性表的链式存储 2.4 一元多项式的表示及相加.
第九章 系 统 安 全 性 9.1 结构体 9.2 结构体型数组  9.3 结构体型指针 9.4 内存的动态分配 9.5 共用体
第4章 鏈結串列(Linked Lists) 4-1 動態記憶體配置-(6) 4-2 鏈結串列的基礎-(7)
Linked List Operations
第3章 栈和队列 3.1 栈 3.2 队列 3.3 应用.
Chapter 5 Tree & Binary Tree
單向鏈結串列 Singly Linked Lists.
第2章 线性表 线性结构 是一个数据元素的有序集合。.
第6章 佇列(Queues) 6-1 佇列的基礎 6-2 佇列的表示法 6-3 環狀佇列 6-4 雙佇列.
第7章 结构体、联合体和枚举类型 本章导读 本章主要知识点 《 C语言程序设计》 (Visual C++ 6.0环境)
程式設計 博碩文化出版發行.
Chapter3 Data Representation
佇列 (Queue).
資料結構 第5章 佇列.
Chap 3 堆疊與佇列 Stack and Queue.
补充内容 结构体 概述 定义结构体类型和定义结构体变量 结构体变量的引用 结构体变量的初始化 指针与结构体 用typedef定义类型的别名.
第五章 数组和 广义表 数组 稀疏矩阵 广义表.
第五章 数组和广义表.
第七章 搜索结构 静态搜索结构 二叉搜索树 AVL树.
Array & General List.
·线性表的定义及ADT ·线性表的顺序存储结构 ·线性表的链接存储结构 · 单向循环链表 · 双链表、双向循环链表 · 一元多项式的加法
第2章 线性表(三) 1/.
Ch.3 栈和队列 黄刘生 中国科学技术大学计算机系 国家高性能计算中心(合肥)
授课老师:龚涛 信息科学与技术学院 2018年3月 教材: 《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
程序设计期末复习 黎金宁
第2章 线性表 2.1 线性表的基本概念 2.2 线性表的顺序存储 2.3 线性表的链式存储 2.4 线性表的应用 2.5 有序表 本章小结.
第3章 栈和队列(二) 1/.
第2章 线性表 线性表抽象数据类型 顺序表 主要知识点 单链表 循环单链表 循环双向链表 静态链表 设计举例.
第十章 C高级程序应用—链表* 10.1链表的基本概念 10.2单向链表 10.3双向链表 10.4应用举例.
第5章 堆疊(Stacks) 5-1 堆疊的基礎 5-2 堆疊的表示法 5-3 堆疊的應用 - 運算式的計算與轉換
第3章 堆栈和队列 堆栈 堆栈应用 队列 队列应用 优先级队列 主要知识点.
第 3 讲 线性表(一).
第3章 栈和队列(一).
第二章 线性表.
資料結構與C++程式設計進階 堆疊與佇列(Stack & Queue) 講師:林業峻 CSIE, NTU 6/ 21, 2010.
第一章 绪论.
数 据 结 构 Ch.4 串 计 算 机 学 院 肖明军
五、链 表 1、单链表 2、双向链表 3、链表应用.
陈海明 副教授 信息学院 计算机系 电子信息类非计算机专业选修课 程序设计实践 陈海明 副教授 信息学院 计算机系
内容回顾 线性表的定义和特点 线性表的顺序存储及查找、插入和删除.
第三章 栈和队列.
資料結構 第4章 堆疊.
第三章 链表 单链表 (Singly Linked List) 循环链表 (Circular List) 多项式及其相加
王玲 第 2 章 线性表 王玲 2019/2/25.
3.1 线性表及逻辑结构 3.2 线性表的顺序存储 3.3 线性表的链式存储 3.4 链式存储结构的应用
第三章 链表 单链表 循环链表 多项式及其相加 双向链表 稀疏矩阵.
7.1 广义表的概念 广义表是n(n≥0)个数据元素组成的序列,其中每个数据元素或是单个数据元素(简称原子),或仍然是一个广义表 。
常宝宝 北京大学计算机科学与技术系 数据结构(三) 常宝宝 北京大学计算机科学与技术系
第五章 递归与广义表 递归的概念 递归过程与递归工作栈 递归与回溯 广义表.
第十章 结构体与链表 西安工程大学.
第二章 数组 作为抽象数据类型的数组 顺序表 多项式抽象数据类型 稀疏矩阵 字符串 小结.
第六章 树和二叉树 学习要点 理解树的定义和基本术语,重点了解二叉树的定义、性质、存储结构; 掌握二叉树遍历的递归算法及它的典型运算;
保留字與識別字.
第四章 栈和队列 栈 ( Stack ) 队列 ( Queue ) 优先队列 (Priority Queue) 小结.
本教學投影片係屬教科書著作之延伸,亦受著作權法之保護。
第二章 线性表.
C++语言程序设计教程 第2章 数据类型与表达式 第2章 数据类型与表达式 制作人:杨进才 沈显君.
#include <iostream.h>
第二章 Java基本语法 讲师:复凡.
第4章 鏈結串列(Linked Lists) 4-1 動態記憶體配置-(6) 4-2 鏈結串列的基礎-(7)
第三章 线性表 3.1 线性表的类型定义 3.2 顺序存储的线性表 3.3 链式存储的线性表 3.4 有序表 3.5 顺序表和链表的综合比较.
Chapter 2 Entity-Relationship Model
第六章 复合数据类型 指针的声明与使用 数组的声明与使用 指针与数组的相互引用 字符串及相关库函数 new与delete
Presentation transcript:

第二章 线性表 1 线性表的逻辑结构及其基本操作 2 线性表的顺序存储结构 3 线性表的链式存储结构 4 静态链表 5 应用实例

2.1. 线性表的逻辑结构及其基本操作 1.线性表的定义: D0为某个数据对象的集合 N为线性表长度 2.1. 线性表的逻辑结构及其基本操作 1.线性表的定义: 线性表是n(n>=0)个相同类型数据元素a0, a1, …,an-1构成的有限序列。 形式化定义: Linearlist = (D, R) 其中: D0为某个数据对象的集合 N为线性表长度

2. 线性表的逻辑特征 对一个非空的线性表,有且仅有一个开始结点a1,它没有直接前驱;有且仅有一个终端结点an,它没有直接后继;其它的内部结点ai点都有且仅有一个直接前驱ai-1和直接后继ai+1. 3. 线性表的两个特征 (1)同类性: 每个数据元素ai都必须是相同类型的数据; (2)有序性: 数据元素在表中的位置决定了它的序号.

4. 线性表的运算 (1) 置空表:建立一个空表; (2) 存 取:访问线性表的某个元素,使用或改变其值; (2) 存 取:访问线性表的某个元素,使用或改变其值; (3) 插 入:在第i个位置插入一个同类型的结点; (4) 删 除:删除第i个结点; (5) 求表长:求出线性表中结点的个数; (6) 查 找:在线性表中查找满足某种条件的结点; (7) 合 并:将两个线性表合并成一个线性表; (8) 分 拆:将一个线性表分拆成多个线性表; (9) 排 序:按某数据项的值递增或递减的顺序重新排列; (10)显示,建立,读写盘等.

第二章 线性表 1 线性表的逻辑结构及其基本操作 2 线性表的顺序存储结构 3 线性表的链式存储结构 4 静态链表 5 应用实例

2.2 线性表的顺序存储结构--顺序表 1. 顺序表的定义 用一组地址连续的存储单元依次存放线性表的元素。 顺序存储结构的特点为: 1)表中逻辑上相邻的结点,存储在相邻的物理位置上;2)可以随机存取表中的元素;3)存储密度大,存储空间利用率高。

2. 线性表的地址计算: 设线性表的基地址为LOC(a1), ai的存储地址为: LOC(ai) = LOC(a1)+(i-1)*k 1<=i<=n 1 a1 Loc(a1) a1 2 a2 Loc(a1)+k a2 … … i ai Loc(a1)+(i-1)*k ai … … n an Loc(a1)+(n-1)*k an

3. 顺序表的类定义 template<class Type>class Array { private: Type *elements; //数组元素 int ArraySize; //数组元素的个数 int MaxSize; //数组元素的最大个数 BOOL GetArray(); BOOL GetArray(Type *pa); };

public: Array(int Size=DefaultSize); Array(Type *pa,int Size=DefaultSize); Array(const Array<Type> &x); ~Array(){ delete []elements; }; Array<Type> & operator = (const Array<Type> &A); Type & operator [] (int i); operator Type * () const { return elements; }; void ClearAll() { ArraySize=0; }; void Init(int size){ ArraySize=size;GetArray(); }; BOOL Delete(int k);//删除第k项 BOOL Insert(int k,Type x);//将数据x插在第k项 int Length() const { return ArraySize; }; int GetMax() const { return MaxSize; };

4. 顺序表上的基本运算-插入 template<class Type> BOOL Array<Type>::Insert(int k,Type x) { if(k<0 || k>=ArraySize || ArraySize==MaxSize) return false; for(int i=ArraySize-1;i>=k;i--) elements[i+1]=elements[i]; elements[k]=x; ArraySize++; return true; }

4. 顺序表上的基本运算-删除 template<class Type> BOOL Array<Type>::Delete(int k)//删除第k项 { if(k<0 || k>=ArraySize) return false; for(int i=k;i<ArraySize-1;i++) elements[i]=elements[i+1]; ArraySize--; return true; }

算法复杂性分析 1、插入 n/2 2、删除 (n-1)/2 3、按序号检索 O(1) 4、按内容检索 (n+1)/2

顺序表的优点: 顺序表的缺点: 无须为表示节点间的逻辑关系而增加额外的存储 空间 可以方便的随机存取表中的任一节点 插入和删除运算不方便 无须为表示节点间的逻辑关系而增加额外的存储 空间 可以方便的随机存取表中的任一节点 顺序表的缺点: 插入和删除运算不方便 由于要求占用连续的存储空间,存储分配只能预先进行

第二章 线性表 1 线性表的逻辑结构及其基本操作 2 线性表的顺序存储结构 3 线性表的链式存储结构 4 静态链表 5 应用实例

2.3 线性表的链式存储——单链表 h 不带头节点的链表 h 带头节点的链表

单链表结点类的定义:C++ template<class Type> class SListnode { friend class SList<Type>; private: Type data; SListnode<Type> *next; public: SListnode(){next=NULL;} SListnode(Type data) { this->data=data;next=NULL; } SListnode(const Type &data,SListnode<Type> *next) { this->data=data;this->next=next; } SListnode *nextnode(){return next;} Type Getdata(){ return data; } SListnode<Type> *Getnext(){ return next; } };

单链表结点类的定义:C# public class SListNode { public SListNode(int NewData) data=NewData; next=null; } public int data; public SListNode next;

单链表类的定义:C++ template<class Type> class SList// { private: SListnode<Type> *head; SListnode<Type> *current; };

public: SList(); SList(char *fn); void Create(int n,bool InsertInHead); ~SList(); void MakeEmpty(); int Length() const; void SetCurrent(SListnode<Type> *cp) { current=cp; } SListnode<Type> *GetCurrent() { return current; } SListnode<Type> *Getnext() { return current->next; } SListnode<Type> *Gethead(){ return head; } SListnode<Type> *Find(Type value); SListnode<Type> *Getnode(int i);

void Insert(Type value,int i); void Insert(Type value){Insert(value,1);}; void Insert(Type value,bool before); void Remove(Type value); void Delete(int i); void Delete(); Type *Getdata(int i); Type *Current(); Type *First(); Type *Next(); void Modifydata(Type value) {current->data=value;} void Invert();

单链表类的定义:C# public class Slist { private ListNode Head; // 头指针 private ListNode Current; // 当前指针 public Slist() Head=null; Current=null; } void MakeEmpty();//清空单链表 public void Insert(int value, bool before); public void Delete() //删除当前的数据

头插法建立单链表 head ④ ③ s ① ② ① 建立新节点 ② 向新节点中添入内容 ③ 使新节点指向链首 ④ 改变头指针

头插法建立单链表 linklist *CREATELIST() { char ch; linklist *head,*s; head=NULL; ch=getchar(); while (ch!=‘$’) { s=malloc(sizeof(linklist)); s->data=ch; s->next=head; head=s; } return(head);

尾插法建立单链表 head ③ ④ s ① ② ① 建立新节点 ② 向新节点中添入内容 ③ 将新节点链入链尾 ④ 改变尾指针

单个节点的后插操作 p ④ ③ s ① ② ① 建立新节点 ② 向新节点中添入内容 ③ 将新节点链入链中 ④ 改变新节点前一节点的指针

单个节点的前插操作 q p ③ ⑤ ④ s ① ② ① 建立新节点 ② 向新节点中添入内容 ③ 查找插入点 ④ 将新节点链入链中 ⑤ 改变新节点前一节点的指针

改进的前插操作 p a s p p ④ x ⑤ ③ s a ① ②

单链表的插入 C++ template<class Type> void SList<Type>::Insert(Type value,bool before) { if(current==head) before=false; SListnode<Type> *newnode; if(before) SListnode<Type> *p=head; while(p->next!=current) p=p->next; newnode=new SListnode<Type>(value,p->next); p->next=newnode; } else newnode=new SListnode<Type>(value,current->next); current->next=newnode; current=newnode;

单链表的插入 C# public void Insert(int value,bool before) { if(current==head) before=false; SListnode newnode; if(before) SListnode p=head; while(p.next!=current) p=p.next; newnode=new SListnode(value,p.next); p.next=newnode; } else newnode=new SListnode(value,current.next); current.next=newnode; current=newnode;

删除后继节点 p ② ① ③ r 存储池

删除后继结点 删除运算 DELETEAFTER(linklist *p) { linklist *r; r=p->next; p->next=r->next; free(r); }   删除运算 DELETE(linklist *L,int i) { linklist *p; int j; j=i-1; p=GET(L,j); if((p!=NULL)&&(p->next!=NULL)) DELETEAFTER(p); else printf(“error\n”); }

循环链表 head rear 非空表 head rear 空表

采用尾指针的循环链表 rear

两循环链表的链接 ra rb ④ p ① ② ③ 存储池

两循环链表的链接 linklist *CONNECT(linklist *ra,linklist *rb) { linklist *p; p=ra->next; ra->next=rb->next->next; free(rb->next); rb->next=p; return rb; }

双链表结点的描述 typedef struct dnode { datatype data; struct dnode *prior,*next; } dlinklist;

双链表的前插操作 DINSERTBEFORE(dlinklist *p,datatype x) { dlinklist *s; s=malloc(sizeof(dlinklist)); s->data=x; s->prior=p->prior; s->next=p; p->prior->next=s; p->prior=s; } p x ⑤ ③ ⑥ ④ s a ① ②

双链表的删除操作 DELETENODEp(dlinklist *p) { p->prior->next=p->next; p->next->prior=p->prior; free(p); }

第二章 线性表 1 线性表的逻辑结构及其基本操作 2 线性表的顺序存储结构 3 线性表的链式存储结构 4 静态链表 5 应用实例

静态链表的定义如下: #define maxsize 1024 \\存储池最大容量 typedef int datatype; typedef int cursor; typedef struct \\结点类型 { datatype data; cursor next; } node;   node nodepool[maxsize]; \\存储池 cursor av;

初始化可用空间表av INITIALIZE() { int i; for (i=0;i<maxsize-1;i++) nodepool[i].next=i+1; nodepool[maxsize-1].next=NULL; av=1; }

data next 1 2 av 3 1 4 … Maxsize-1 Maxsize-1 NULL

结点的分配算法 cursor GETNODE() { cursor p; if (av==NULL) p=NULL; else { p=av; av=nodepool[av].next; } return p;

结点的回收算法 FREENODE(cursor p) { nodepool[p].next=av; av=p; }

静态链表查找算法 cursor FINDSTLIST(cursor L,int i) { cursor p; int j; p=L; j=0; while ((nodepool[p].next!=NULL)&&(j<i)) { p=nodepool[p].next; j++; } if (i==j) return(p); else return NULL;

静态链表插入算法 int INSERTSTLIST(cursor L,datatype x,int i) { cursor p,s; p=FINDSTLIST(L,i-1); if (p!=NULL) { s=GETNODE(); if (s==NULL) { printf(“error\n”); return NULL;} else { nodepool[s].data=x; nodepool[s].next=nodepool[p].next; nodepool[p].next=s; return(1); } { printf(“error\n”); retur NULL;}

静态链表删除算法 DELETESTLIST(cursor L,int i) { cursor p,q; p=FINDSTLIST(L,i-1); if ((p!=NULL)&&(nodepool[p].next!=NULL) { q=nodepool[p].next; nodepool[p].next=nodepool[q].next; FREENODE(q); } else printf(“error\n”);

顺序表与链表的比较 1、基于空间的考虑 2、基于时间的考虑 3、基于语言的考虑

第二章 线性表 1 线性表的逻辑结构及其基本操作 2 线性表的顺序存储结构 3 线性表的链式存储结构 4 静态链表 5 应用实例

应用实例 以单链表存储结构实现线性表的就地逆转 1、全局变量法 2、参数法

la p p la q p p la q p p la p p la 单链表的逆转

Linklist *la; Void convers1() linklist *p,*q; P = la->next; la->next = NULL; While (p != NULL); { q = p; p = p->next; q->next = la->next; la->next = q; }

Void convers2(linklist *la) linklist *p,*q; P = la->next; La->next = NULL; While (p != NULL); { q = p; p = p->next; q->next = la->next; la->next = q; }

例:在一个给定的线性表中删除元素值在x到y之间的所有元素,要求以较高的效率实现 算法思想:先将向量A中所有在x到y之间的元素置成一个特殊的值0,并不立即删除它们,然后从最后向前依次扫描,删除为0的元素,移动后面的元素。

void del(A,n,x,y) int A[]; int n,x,y; { int i,k; for (i=1; i<=n; i++) if (A[i]>=x && A[i]<=y) A[i]=0; for (i=n; i>=1; i--) if (A[i]=0) { for (k=i; k<=(n-1); k++) A[k] = A[k+1]; n--; }

例:用不多于3n/2的平均比较次数,在一个线性表中找出最大和最小值的元素 void maxmin(A,n) int A[]; int n; { int max, min, i; for (i=2; i<=n; i++) if (A[i] > max) max = A[i]; else if (A[i] < min) min = A[i]; printf(“max = %d, min = %d\n”, max, min); }

分析: 最坏情况:元素以递减顺序排列,(A[i]>max)和 (A[i]<min) 均需比较 n-1 次,所以总的比较次数为:2(n-1) 最好情况:元素以递增顺序排列,(A[i]>max)均成立,不须进行 (A[i]<min) 的比较,所以总的比较次数为:(n-1) 平均: (2(n-1)+n-1)/2 = 3n/2 – 3/2

例:一元多项式的相加 typedef struct pnode { float coef; //系数 int exp; //指数 struct pnode *next; //指向下一节点 } polynode; coef exp next

多项式 2 + 3X + 5X3 + 2X4 可表示为: 多项式 2 + 3X + 5X3 + 2X4 3 + 2X + 4X2 相加 -1 -1 2 3 1 5 3 2 4 多项式 2 + 3X + 5X3 + 2X4 3 + 2X + 4X2 相加

算法思想: 初始化; While (两个链都没处理完) { if (指针指向当前节点的指数项相同) {系数相加,在C链中天加新的节点; A、B链的指针均前移;} else {以指数小的项的系数添入C链中的新节点; 指数小的相应链指针前移;} } While(A链处理完) { 顺序处理B链;} While(B链处理完) { 顺序处理A链;}

q1 A -1 2 3 1 5 3 2 4 q2 B -1 3 2 1 4 2 C -1

q1 A -1 2 3 1 5 3 2 4 q2 B -1 3 2 1 4 2 C -1 5

q1 A -1 2 3 1 5 3 2 4 q2 B -1 3 2 1 4 2 C -1 5 5 1

q1 A -1 2 3 1 5 3 2 4 q2 B -1 3 2 1 4 2 C -1 5 5 1 4 2 …………

第二章 线性表 1 线性表的逻辑结构及其基本操作 2 线性表的顺序存储结构 3 线性表的链式存储结构 4 静态链表 5 应用实例