41
算算算算算算算 Algorithms and Data Structures 算算算 算算算算算算

算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

  • View
    311

  • Download
    16

Embed Size (px)

Citation preview

Page 1: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

算法与数据结构Algorithms and Data Structure

s 第八章 动态存储管理

Page 2: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

第八章 动态存储管理第八章 动态存储管理8.1 概述 内存是很重要的、很昂贵的资源,如何合理高效地使用这一资源是一个比较复杂的问题。 早期使用低级语言编程,内存管理是由程序员自己负责。程序员负担重,管理水平因人而异,管理效率低,容易出错。 随着操作系统和高级语言的发展,情况不断改善。内存管理分别由操作系统、高级语言的编译系统和程序员分工合作管理。通常编译系统负责静态储存管理,操作系统负责整个内存管理和动态储存管理。

Page 3: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

程序员级的管理: 用户程序中所用的储存结构有两种,静态结构 :空间量在编译后,即可确定 动态结构:程序运行中申请空间,编译时无法确定。静态储存由编译系统管理。动态储存由程序员和操作系统管理,但程序员的管理非常简单。程序员的工作就是在需要的时候向系统申请空间,在不需要时释放要来的动态储存空间: C 语言中: malloc(size), 申请 size 字节的内存;

free(p), 释放 p ,归还给系统; C++ 中: new objectType(), 申请空间; free(p), 释放 p ,归还给系统;

Page 4: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

Java 语言中: new objectType(), 申请空间;

用户程序:# include iostd.lib……Int main() {… *r=new int[100];…

free (r);…}

操作系统

分配 OS_AllocMemory(r,size,flags)

回收 OS_ReclaimMemory(r)

FreeMem

FreeMem

rFreeMem

Page 5: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

编译系统级管理 在编译中,编译系统为程序设置了一个虚拟空间,它管理的是虚拟空间。

用户程序:…int x,y;float r,s;char str[10]; ………

虚拟空间:x: 4bytesy: 4bytes

str: 10bytes

r: 4bytess: 4bytes

0481216

26

内存

程序装入时,重定位

编译原理与技术中将做介绍。

Page 6: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

操作系统级管理: 存储管理是操作系统的重要部分之一,操作系统对储存的管理是才是真实的管理,而且这一管理是很复杂的。

操作系统的存储管理

为程序代码和静态数据分配空间

为程序动态分配空间

回收不用的动态空间

回收空间程序代码和静态数据空间

执行程序

执行完毕或撤消执行程序

程序

New Otype()

Free(p)

Page 7: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

从外部来看,操作系统存储管理系统就是提供存储空间分配和回收服务,但内部实现方法却十分复杂,不同的操作系统采用不同的策略和方法,这些问题将在后续课程操作系统中详细介绍。 这里我们只是站在数据结构的角度来讨论动态存储管理的基本方法,即存储空间的分配和回收基础技术、存储空间的逻辑结构和物理结构。

Page 8: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

8.2 可利用空间表 初试状态

OS bootOS 占用空间

free tagsizelink

一个连续的存储空间称为“块” [block]

Tag :标记空间是否分配

Size :空间大小

Link :指向下一个空闲块

初试状态:除了操作系统占用的空间外,其它空间形成一个空闲块。当空闲块多时,用 link 链成一个链表,该链表就是可利用空间表。初试此表中只有一个空闲块。表指针是 free 。

Page 9: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

经过多次分配、回收之后,形成了多个空闲块,它们之间不连续,如图所示:

Free

used1

used2

used3

used4

used52 3 4 5 6

Free

1

1

3 6 5 4 2

Page 10: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

可利用空间表的链接顺序有: ( 1 )按块的首地址有低到高链接; ( 2 )按块的大小有小到大链接; ( 3 )按块的大小有大到小链接;分配: 一般有 3 种策略,设申请空间的大小为 n

( 1 )首次拟合法:从表头开始搜索,遇到第一个尺寸等于大于 n 的块进行分配;

( 2 )最佳拟合法:搜索整个表,将最小的等于大于 n 的块进行分配;

( 3 )最差拟合法:搜索整个表,将最大块进行分配(等于大于 n );

Page 11: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

分配过程:• 找到合适的空闲块 p ;• P.size等于 n 或比 n 大少许(一般设定一个量

s ),则将 p 从表中删除,进行分配;• 若 p.size>n+s ,从 p 的下部切割 size 为 n 的一块进行分配,如图所示: n=16k

0 64kp

1 16k

48k

Page 12: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

回收 : 程序释放空间 ( 如 free(p)) 、程序运行结束后将占用的块归还系统,如果收回的块的相邻块是空闲的,需要合并它们。

回收过程:设释放块是 p ,大小为 size 。( 1 ) 设置 p .tag=0 ;( 2 )判断 p 的下相邻块 q 是否空闲

若空闲:从可利用空间表摘出 q ,置 p.size=p.size+q.size( 合并 ) ;

( 3 )判断 p 的上相邻块 r 是否空闲 若空闲:合并 r 和 p , r.size=r.size+p.size

否则:将 p插入可利用空间表。

Page 13: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

例如:Free

used1

used2

used3

used4

used52 3 4 5 6

Free

1

13 6 5 4 2

释放 used1

0 4k

1 1k null

0 6k

1

2

used1

0 4k

0 7k null1

2

used1

0 11k1

2

used1

Page 14: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

有时也不必马上合并,如果释放块 p 的大小恰好符合下次申请空间的要求,可以将 p 分配,而不必从可利用空间表中切割分配。

Free

13 6 5 4

2

used1

Page 15: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

例如,一个使用单链表的程序,它会不断地申请和释放同类型的结点(块大小相等),1 回收时不进行合并,而是放在另一个链表 avail中;2 分配时首先从 avail取一个块分配,当 avail 中没有空闲块时在从 free 表里分配。这样就省去了不断地合并切割的麻烦,可以提高效率。 对于一些小的操作系统,内存管理相对简单些。在许多专用设备、智能仪表和家用电器等都使用一种小型的、高效的、简单的操作系统,一般称之为“嵌入式操作系统”。下面介绍一些实用而简单的动态存储管理系统。

Page 16: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

8.3 伙伴系统( Buddy system )特点:( 1 )分配块的大小均是 2k ;( 2 )分配和回收简单 可利用空间表结构:

20

21

22

.

.

.

2k

2m

0 k 0 k 0 k

^^^

内存最大空间是 2m

空闲块按其大小链入各自的链表;该数组是各链表的表头接点

同尺寸的空闲块构成双向循环链表;有 4 个域: tag 标记, 0 空闲, 1 占用, k: 块的大小 2k , llink:q前驱指针, rlingk: 后继指针

Page 17: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

伙伴系统抽象数据类型ADT BoddySystem

Data :

int m // 可用内存 2m

FreeHeadList // m 个表头结点构成的线性表

BlockScrpt // 块描述 Memory // 整个内存空间

opration:

BS_malloc(size) // 分配内存 BS_reclaim(BlockScrpt bp) // 回收内存End BlockSystem

Page 18: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

Class FreeHeadNode {

int sizePower; // k 2k

BlockScrpt first; // 链表指针} // Class FreeHeadNode

Class FreeHeadList {

int m; //

FreeHeadNode[] list;

public

FreeHeadList(int n) { m=n;

list=new FreeHeadNode[m] ;}

for (k=0; k<=m; k++) { list[k].sizePower=k; first=null;}

} // Class FreeHeadList

k first

0123..

m-1m

^^^

^

^

Page 19: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

块描述Class BlockScrpt {

int sizePower;

boolean used;

BlockScrpt llink, rlink;

int add;

public

BlockScrpt(int k, boolean b, int addr) {

sizePower=k; used=b; add=addr;

} // BlockScrpt

}// Class BlockScrpt

Page 20: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

伙伴系统结构Class BuddySystem { int m; // 最大可用内存 2m

BlockHeadList headList // 表头向量 BlockScrpt blkScrpt; // 块描述 Byte[] mem; // 内存 public BuddySystem(int k) { // 构造函数 m=k; headList=new BlockHeadList(m); blkScrpt=new BlockScrpt(m,false,0);

Page 21: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

blkScrpt.llink=blkscrpt; blkScrpt.rlink=blkscrpt; headList[m].first= blkScrpt mem=new Byte[2m]; } // BlockScrpt BS_malloc(int k) {……} void BS_reclaim(BlockScrpt bp) {……}}// Class BuddySystem

Page 22: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

初始状态

012..k..m false m 0

012

2m-1

headList

mem

BlockScrpt

Page 23: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

分配 26 之后

..67..k.m-1m

false m-1 2m-1

0

2m-1

2m-1

headList mem

false k 2k

false 7 27

true 6 0

false 6 26

Page 24: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

分配算法思想:申请空间量为 2k ;1 从 k 到 m依次搜寻非空链表若无:内存不够,结束;

若有:设为 headList[j] k=<j<=m

2 若 j=k: 从 headList[k] 中取一结点分配,结束;3 若 j>k: 从 headList[j]取一结点 bs

(1) 将 bs均分为二,高地址部分插入 headList[j-1];

j--;

(2) 重复( 1 )直到 j=k ;4 将 bs 分配;结束;

Page 25: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

BlockScrpt BS_malloc(int k) { for (j=k; j<=m; j++) // 找非空链表 if (!headList[j].first) break; if (j>m) return null; // 无非空链表,分配失败 bs=headList[j].delet(1); // 从非空链表中取第一个接点; for (s=j; s>k; s--){ // 将大块分割; bst=new BlockScrpt(s-1, false, bs.add+2s-1); headList[s-1].insert(bst); bs.sizePower--; } // for bs.used=true; return bs; // 分配 bs} //

True s-1

False s-1 bst

bs

Page 26: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

回收算法思想 伙伴系统的一个重要特点是:任何块(除最大块外)都有唯一的一个伙伴,所谓伙伴即:大小一样且相邻; 空闲的相邻块是可以合并的; 一个块的伙伴地址是什么? 设块的首地址是 p ,其伙伴的首地址是: Buddy(p, k) = p+2k (if p MOD 2k+1=0) = p +2k (if p MOD 2k+1= 2k)

Page 27: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

设回收的块是 bs

1 k=bs.sizePower; p=bs.add;2 计算 伙伴地址 q=buddy(p,k);3 从 headList[k]链表中找add等于 q的块描述bst,

若无:伙伴占用,将 bs 插入 headList[k],结束; 否则:将 bs和 bst合并,用 bs 描述。 K++;4 重复 3 直到 k>m;5 将 bs 插入 headList[m]。

Page 28: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

8.4 一个小型的动态存储管理系统

Page 29: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

算法 6.8:中序遍历线索二叉树

Page 30: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

算法 6.9: 求p的后继( p在前序序列中的后继 )

Page 31: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

算法 6.10: 前序遍历线索二叉树

Page 32: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

6.4 6.4 森林与二叉树森林与二叉树

Page 33: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

6.5 6.5 归并查找集(归并查找集( Merge Find Set MFSMerge Find Set MFS ))

Page 34: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

改进后算法:

Page 35: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理
Page 36: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

Huffman算法:

Page 37: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

算法 6.11 Huffman编码

Page 38: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

void initiate(char c[], float w[]) {

Page 39: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

void selectMin(int k, int &s, int &t){

Page 40: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理

void getCode(){

Page 41: 算法与数据结构 Algorithms and Data Structures 第八章 动态存储管理