mirror of
https://github.com/kangjianwei/Data-Structure.git
synced 2026-10-01 22:23:30 +08:00
💡 <08 动态存储管理>习题代码
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
#include <stdio.h>
|
||||
#include "Status.h"
|
||||
#include "SqStack.h"
|
||||
|
||||
/* 宏定义 */
|
||||
#define MAXSIZE 200 // 内存总大小
|
||||
|
||||
|
||||
/* 空闲空间类型定义 */
|
||||
typedef struct {
|
||||
void* base; // 可用空间内存的起始地址
|
||||
int size; // 空闲空间大小(按字节计数)
|
||||
SqStack block; // 已经使用的内存块大小,先申请的内存信息先入栈
|
||||
} Space;
|
||||
|
||||
|
||||
// 初始化内存空间及内存信息栈
|
||||
void InitSpace(Space* space);
|
||||
|
||||
// 打印内存布局,查看当前内存的使用情况
|
||||
void PrintMemoryLayout(Space space);
|
||||
|
||||
// 申请大小为n的内存块,返回申请到的内存起始地址
|
||||
void* Algo_8_11(Space* space, int n);
|
||||
|
||||
// 回收内存,遵循"最后分配者最先释放"的原则
|
||||
Status Algo_8_12(Space* space);
|
||||
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
Space space;
|
||||
int s[5] = {50, 50, 150, 100, 50}; // 定义内存申请数量
|
||||
int i;
|
||||
|
||||
// 初始化内存
|
||||
InitSpace(&space);
|
||||
PrintMemoryLayout(space);
|
||||
printf("\n");
|
||||
|
||||
// 申请/释放内存
|
||||
for(i = 0; i < 5; i++) {
|
||||
printf("申请 %d 个内存后...\n", s[i]);
|
||||
Algo_8_11(&space, s[i]);
|
||||
PrintMemoryLayout(space);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// 初始化一块空闲空间
|
||||
void InitSpace(Space* space) {
|
||||
// 申请MAX字节的空间(假设总能初始化成功)
|
||||
space->base = malloc(MAXSIZE);
|
||||
space->size = MAXSIZE;
|
||||
|
||||
// 初始化内存信息栈
|
||||
InitStack(&(space->block));
|
||||
}
|
||||
|
||||
// 打印内存布局,查看当前内存的使用情况
|
||||
void PrintMemoryLayout(Space space) {
|
||||
int i;
|
||||
|
||||
for(i = 1; i <= MAXSIZE; i++) {
|
||||
if(i <= space.size) {
|
||||
printf("□");
|
||||
} else {
|
||||
printf("■");
|
||||
}
|
||||
|
||||
// 预定每隔20个换一下行
|
||||
if(i % 20 == 0) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
if(MAXSIZE % 20 != 0) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
// 申请大小为n的内存块,返回申请到的内存起始地址
|
||||
void* Algo_8_11(Space* space, int n) {
|
||||
|
||||
/*
|
||||
* 如果可用的内存数量少于申请的内存数量,
|
||||
* 则需要释放最近申请使用的内存以腾出空间。
|
||||
*/
|
||||
while(space->size < n && Algo_8_12(space) == OK) {
|
||||
// 直到空闲内存满足申请要求,或者全部占用内存已经释放,才会退出循环
|
||||
}
|
||||
|
||||
// 如果没有足够的内存可用,则返回空指针
|
||||
if(space->size < n) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 可用空间减小
|
||||
space->size -= n;
|
||||
|
||||
// 记下成功申请到的内存
|
||||
Push(&(space->block), n);
|
||||
|
||||
// 返回申请到的内存起始地址
|
||||
return space->base + space->size;
|
||||
}
|
||||
|
||||
// 回收内存,遵循"最后分配者最先释放"的原则
|
||||
Status Algo_8_12(Space* space) {
|
||||
int e;
|
||||
|
||||
// 已经没有可释放内存时,返回ERROR
|
||||
if(StackEmpty(space->block)) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// 将最后申请的内存释放掉
|
||||
Pop(&(space->block), &e);
|
||||
|
||||
// 可用空间增大
|
||||
space->size += e;
|
||||
|
||||
return OK;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
# 包含公共库
|
||||
include_directories(${CMAKE_SOURCE_DIR}/Status)
|
||||
|
||||
# 生成可执行文件
|
||||
add_executable(08.11-08.12 SqStack.h SqStack.c 08.11-08.12.c)
|
||||
# 链接公共库
|
||||
target_link_libraries(08.11-08.12 Scanf_lib)
|
||||
|
||||
# 记录要拷贝到*.exe目录下的资源文件
|
||||
file(GLOB TestData TestData*.txt)
|
||||
# 将资源文件拷贝到*.exe目录下,不然无法加载
|
||||
file(COPY ${TestData} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
@@ -0,0 +1,90 @@
|
||||
/*=========================
|
||||
* 栈的顺序存储结构(顺序栈)
|
||||
==========================*/
|
||||
|
||||
#include "SqStack.h" //**▲03 栈和队列**//
|
||||
|
||||
/*
|
||||
* 初始化
|
||||
*
|
||||
* 构造一个空栈。初始化成功则返回OK,否则返回ERROR。
|
||||
*/
|
||||
Status InitStack(SqStack* S) {
|
||||
if(S == NULL) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
(*S).base = (SElemType*) malloc(STACK_INIT_SIZE * sizeof(SElemType));
|
||||
if((*S).base == NULL) {
|
||||
exit(OVERFLOW);
|
||||
}
|
||||
|
||||
(*S).top = (*S).base;
|
||||
(*S).stacksize = STACK_INIT_SIZE;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* 判空
|
||||
*
|
||||
* 判断顺序栈中是否包含有效数据。
|
||||
*
|
||||
* 返回值:
|
||||
* TRUE : 顺序栈为空
|
||||
* FALSE: 顺序栈不为空
|
||||
*/
|
||||
Status StackEmpty(SqStack S) {
|
||||
if(S.top == S.base) {
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 入栈
|
||||
*
|
||||
* 将元素e压入到栈顶。
|
||||
*/
|
||||
Status Push(SqStack* S, SElemType e) {
|
||||
if(S == NULL || (*S).base == NULL) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// 栈满时,追加存储空间
|
||||
if((*S).top - (*S).base >= (*S).stacksize) {
|
||||
(*S).base = (SElemType*) realloc((*S).base, ((*S).stacksize + STACKINCREMENT) * sizeof(SElemType));
|
||||
if((*S).base == NULL) {
|
||||
exit(OVERFLOW); // 存储分配失败
|
||||
}
|
||||
|
||||
(*S).top = (*S).base + (*S).stacksize;
|
||||
(*S).stacksize += STACKINCREMENT;
|
||||
}
|
||||
|
||||
// 进栈先赋值,栈顶指针再自增
|
||||
*(S->top++) = e;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* 出栈
|
||||
*
|
||||
* 将栈顶元素弹出,并用e接收。
|
||||
*/
|
||||
Status Pop(SqStack* S, SElemType* e) {
|
||||
if(S == NULL || (*S).base == NULL) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
if((*S).top == (*S).base) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// 出栈栈顶指针先递减,再赋值
|
||||
*e = *(--(*S).top);
|
||||
|
||||
return OK;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*=========================
|
||||
* 栈的顺序存储结构(顺序栈)
|
||||
==========================*/
|
||||
|
||||
#ifndef SQSTACK_H
|
||||
#define SQSTACK_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> // 提供malloc、realloc、free、exit原型
|
||||
#include "Status.h" //**▲01 绪论**//
|
||||
|
||||
/* 宏定义 */
|
||||
#define STACK_INIT_SIZE 100 // 顺序栈存储空间的初始分配量
|
||||
#define STACKINCREMENT 10 // 顺序栈存储空间的分配增量
|
||||
|
||||
/* 顺序栈元素类型定义 */
|
||||
typedef int SElemType;
|
||||
|
||||
// 顺序栈元素结构
|
||||
typedef struct {
|
||||
SElemType* base; // 栈底指针
|
||||
SElemType* top; // 栈顶指针
|
||||
int stacksize; // 当前已分配的存储空间,以元素为单位
|
||||
} SqStack;
|
||||
|
||||
|
||||
/*
|
||||
* 初始化
|
||||
*
|
||||
* 构造一个空栈。初始化成功则返回OK,否则返回ERROR。
|
||||
*/
|
||||
Status InitStack(SqStack* S);
|
||||
|
||||
/*
|
||||
* 判空
|
||||
*
|
||||
* 判断顺序栈中是否包含有效数据。
|
||||
*
|
||||
* 返回值:
|
||||
* TRUE : 顺序栈为空
|
||||
* FALSE: 顺序栈不为空
|
||||
*/
|
||||
Status StackEmpty(SqStack S);
|
||||
|
||||
/*
|
||||
* 入栈
|
||||
*
|
||||
* 将元素e压入到栈顶。
|
||||
*/
|
||||
Status Push(SqStack* S, SElemType e);
|
||||
|
||||
/*
|
||||
* 出栈
|
||||
*
|
||||
* 将栈顶元素弹出,并用e接收。
|
||||
*/
|
||||
Status Pop(SqStack* S, SElemType* e);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,65 @@
|
||||
#include <stdio.h>
|
||||
#include "BoundaryTagMethod.h" //**▲08 动态存储管理**//
|
||||
|
||||
/*
|
||||
* 边界标识法的内存回收算法
|
||||
*
|
||||
* 对指针p处的内存进行释放
|
||||
*/
|
||||
void Algo_8_13(Space* pav, Space p);
|
||||
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
Space pav;
|
||||
Space p[12]; // 记录申请到的内存的指针
|
||||
int s[12] = {10, 20, 30, 50, 5, 15, 10, 5, 15, 15, 2, 20}; // 申请的空间大小
|
||||
int i = 0;
|
||||
|
||||
printf("████████ InitSpace \n");
|
||||
{
|
||||
int max = 200; // 初值建议为20的倍数,目的是打印出来可以对齐
|
||||
|
||||
printf("初始化包含 %d 个\"字\"的内存块后,当前内存布局为:\n", max);
|
||||
pav = InitSpace(max);
|
||||
PrintMemoryLayout();
|
||||
printf("\n");
|
||||
}
|
||||
PressEnterToContinue(debug);
|
||||
|
||||
printf("████████ AllocBoundTag \n");
|
||||
{
|
||||
for(i = 0; i < 12; i++) {
|
||||
printf("████ %2d> 申请 %d 个\"字\"的内存后,当前内存布局为:\n", i + 1, s[i]);
|
||||
p[i] = AllocBoundTag(&pav, s[i]);
|
||||
PrintMemoryLayout();
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
PressEnterToContinue(debug);
|
||||
|
||||
printf("████████ FreeBoundTag \n");
|
||||
{
|
||||
// 定义一个指针回收顺序
|
||||
int a[10] = {7, 3, 10, 6, 8, 5, 11, 1, 0, 4};
|
||||
|
||||
for(i = 0; i < 10; i++) {
|
||||
printf("回收 p%d 指向的内存...\n", a[i] + 1);
|
||||
Algo_8_13(&pav, p[a[i]]);
|
||||
PrintMemoryLayout();
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
PressEnterToContinue(debug);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 边界标识法的内存回收算法
|
||||
*
|
||||
* 对指针p处的内存进行释放
|
||||
*/
|
||||
void Algo_8_13(Space* pav, Space p) {
|
||||
FreeBoundTag(pav, p);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,96 @@
|
||||
/*==============
|
||||
* 边界标识法
|
||||
*
|
||||
* 包含算法: 8.1
|
||||
===============*/
|
||||
|
||||
#ifndef BOUNDARYTAGMETHOD_H
|
||||
#define BOUNDARYTAGMETHOD_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "Status.h" //**▲01 绪论**//
|
||||
|
||||
/* 宏定义 */
|
||||
#define e 5 // 分配空间时用到的容差
|
||||
#define FootLoc(p) p+(p->size)-1 // 将p指针定位到p所指内存块的底部
|
||||
|
||||
|
||||
/*
|
||||
* 内存"字"的类型定义
|
||||
*
|
||||
* 所谓"字"是指空间分配的最小单位,它不是字节。
|
||||
* 一个"字"有多大,取决于对"字"结构是如何定义的。
|
||||
*/
|
||||
typedef struct WORD {
|
||||
|
||||
/*
|
||||
* 注:
|
||||
* 教材中将llink和uplink封装在了一个联合体中,个人感觉这个封装有些鸡肋。
|
||||
* 一方面,head和foot的公共部分其实只有tag,如果真想用联合体,那么应当把size和rlink也封装起来。
|
||||
* 另一方面,这个封装节省的空间很有限,而且直接影响了代码的可读性。
|
||||
* 这里只是教学代码,而不是真实的系统代码,所以空间考虑在其次,原理展示为首要任务。
|
||||
* 此外,教材中的伪码中也并没有考虑这个联合体,而是直接进行操作的。
|
||||
* 综上所述,这里去除了教材中的联合体结构。
|
||||
* 如想观察带有联合体的写法,可以参考CFree分支的代码。
|
||||
*/
|
||||
|
||||
int tag; // 块标志,0空闲,1占用,头部和尾部均有
|
||||
|
||||
struct WORD* llink; // 头部域,指向前驱结点
|
||||
struct WORD* rlink; // 头部域,指向后继结点
|
||||
int size; // 头部域,块大小
|
||||
|
||||
struct WORD* uplink; // 底部域,指向本结点头部
|
||||
} WORD;
|
||||
|
||||
typedef WORD* Space; // Space:指向可利用空间的指针类型
|
||||
|
||||
|
||||
/*
|
||||
* 初始化一块大小为n个字的内存,并返回指向该内存的起点的指针
|
||||
* 注:返回的初始内存已经包含了head和foot。
|
||||
*/
|
||||
Space InitSpace(int n);
|
||||
|
||||
/*
|
||||
* ████████ 算法8.1 ████████
|
||||
*
|
||||
* 边界标识法的内存分配算法
|
||||
*
|
||||
* 从空间pav中申请一块大小至少为n的空间,并返回指向申请到的空间的指针。如果分配失败,则返回NULL。
|
||||
* 为了使分配后的剩余块尽量均匀分布,每次分配完之后都要把空间指针pav向前移动,具体描述参见教材。
|
||||
*
|
||||
* 注:
|
||||
* 1.这里采用首次拟合法,即一遇到满足条件的内存块就进行分配操作。
|
||||
* 2.为了避免空间碎片化过快,这里增加了一个容差e,具体含义参考教材描述。
|
||||
* 3.这里申请分配n个字的空间,指的是已经完成换算的空间。
|
||||
* 比如用户想要容量为10个字的空间,但每个空间又包含head和foot这两个字存储空间使用信息,
|
||||
* 因此实际上分配的空间大小应为12个字,这个"12"就是n的含义。
|
||||
* 教材中提到"head和foot在分配时忽略不计",这样是为了伪码书写的方便。实际写代码时,这两个空间是不能忽略的。
|
||||
* 但是如果按照上面的描述,把n解释为已经换算后空间,而不是用户原始申请的空间,
|
||||
* 那么既满足了没有忽略空间,又满足了在书面效果上,跟教材伪码统一,可谓两全其美。
|
||||
*/
|
||||
Space AllocBoundTag(Space* pav, int n);
|
||||
|
||||
/*
|
||||
* 边界标识法的内存回收算法
|
||||
*
|
||||
* 对指针p处的内存进行释放
|
||||
*/
|
||||
void FreeBoundTag(Space* pav, Space p);
|
||||
|
||||
/*
|
||||
* 打印内存布局,查看当前内存的使用情况
|
||||
* 注:仅限内部测试使用
|
||||
*/
|
||||
void PrintMemoryLayout();
|
||||
|
||||
/*
|
||||
* 计算可用的空闲空间容量
|
||||
*
|
||||
* 注:仅限内部使用,用在日志打印中
|
||||
*/
|
||||
static int AvailableSpace(Space pav);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
# 包含公共库
|
||||
include_directories(${CMAKE_SOURCE_DIR}/Status)
|
||||
|
||||
# 生成可执行文件
|
||||
add_executable(08.13 BoundaryTagMethod.h BoundaryTagMethod.c 08.13.c)
|
||||
# 链接公共库
|
||||
target_link_libraries(08.13 Scanf_lib)
|
||||
|
||||
# 记录要拷贝到*.exe目录下的资源文件
|
||||
file(GLOB TestData TestData*.txt)
|
||||
# 将资源文件拷贝到*.exe目录下,不然无法加载
|
||||
file(COPY ${TestData} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
@@ -0,0 +1,66 @@
|
||||
#include <stdio.h>
|
||||
#include "BuddySystem.h" //**▲08 动态存储管理**//
|
||||
|
||||
/*
|
||||
* 伙伴系统的内存回收算法
|
||||
*
|
||||
* 对指针p处的内存进行释放(这类似于free(),只是对内存进行释放操作,至于置空指针p的操作,应交给调用方完成)
|
||||
*
|
||||
* 注:这里没有验证p的取值,调用方应当确保p在合规的范围
|
||||
*/
|
||||
void Algo_8_14(FreeList avail, WORD* p);
|
||||
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
FreeList avail;
|
||||
WORD* p[8]; // 记录申请到的内存的指针
|
||||
int s[8] = {4, 5, 6, 7, 1, 5, 3, 9}; // 申请的空间大小
|
||||
int i;
|
||||
|
||||
printf("████████ InitSpace \n");
|
||||
{
|
||||
printf("初始化一个内存块...\n");
|
||||
InitSpace(avail);
|
||||
PrintMemoryLayout();
|
||||
printf("\n");
|
||||
}
|
||||
PressEnterToContinue(debug);
|
||||
|
||||
printf("████████ AllocBuddy \n");
|
||||
{
|
||||
for(i = 0; i < 8; i++) {
|
||||
printf("申请大小为 %d 个字的内存块...\n", s[i]);
|
||||
p[i] = AllocBuddy(avail, s[i]);
|
||||
PrintMemoryLayout();
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
PressEnterToContinue(debug);
|
||||
|
||||
printf("████████ FreeBuddy \n");
|
||||
{
|
||||
// 定义一个指针回收顺序
|
||||
int a[8] = {2, 0, 5, 7, 1, 4, 3, 6};
|
||||
|
||||
for(i = 0; i < 8; i++) {
|
||||
Algo_8_14(avail, p[a[i]]);
|
||||
PrintMemoryLayout();
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
PressEnterToContinue(debug);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 伙伴系统的内存回收算法
|
||||
*
|
||||
* 对指针p处的内存进行释放(这类似于free(),只是对内存进行释放操作,至于置空指针p的操作,应交给调用方完成)
|
||||
*
|
||||
* 注:这里没有验证p的取值,调用方应当确保p在合规的范围
|
||||
*/
|
||||
void Algo_8_14(FreeList avail, WORD* p) {
|
||||
FreeBuddy(avail, p);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,89 @@
|
||||
/*==============
|
||||
* 伙伴系统
|
||||
*
|
||||
* 包含算法: 8.2
|
||||
===============*/
|
||||
|
||||
#ifndef BUDDYSYSTEM_H
|
||||
#define BUDDYSYSTEM_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include "Status.h" //**▲01 绪论**//
|
||||
|
||||
/* 宏定义 */
|
||||
#define M 6 // 假设总空间大小为2^M个字,子表个数为M+1
|
||||
|
||||
|
||||
/*
|
||||
* 内存"字"的类型定义
|
||||
*
|
||||
* 所谓"字"是指空间分配的最小单位,它不是字节。
|
||||
* 一个"字"有多大,取决于对"字"结构是如何定义的。
|
||||
*/
|
||||
typedef struct WORD {
|
||||
struct WORD* llink; // 头部域的前驱指针
|
||||
struct WORD* rlink; // 头部域的后继指针
|
||||
int tag; // 头部域的块标志,0:空闲,1:占用
|
||||
int kval; // 指示块的大小,比如其值为K时,表示该块的大小为2^K
|
||||
} WORD;
|
||||
|
||||
// 表头向量类型
|
||||
typedef struct HeadNode {
|
||||
int nodesize; // 该链表的空闲块的大小
|
||||
WORD* first; // 该链表的表头指针
|
||||
} FreeList[M + 1];
|
||||
|
||||
|
||||
/*
|
||||
* 初始化一块大小为2^M个字的内存,并返回指向该内存的起点的指针
|
||||
* 注:返回的初始内存已经包含了head。
|
||||
*/
|
||||
void InitSpace(FreeList avail);
|
||||
|
||||
/*
|
||||
* ████████ 算法8.2 ████████
|
||||
*
|
||||
* 伙伴系统的内存分配算法
|
||||
*
|
||||
* 从空间avail中申请一块大小至少为n(原始值)的空间,并返回指向申请到的空间的指针。如果分配失败,则返回NULL。
|
||||
*
|
||||
* 注:
|
||||
* 1.这里采用首次拟合法,即一遇到满足条件的内存块就进行分配操作。
|
||||
* 2.这里申请分配n个字的空间,指的是用户申请的原始空间。
|
||||
* 实际在申请时,还要考虑到每个块前面有1个字的head信息,即经过换算后,实际需要申请(n+1)个字。
|
||||
* 这里的n与算法8.1里面的n含义正好相反,需要注意。
|
||||
*/
|
||||
WORD* AllocBuddy(FreeList avail, int n);
|
||||
|
||||
/*
|
||||
* 伙伴系统的内存回收算法
|
||||
*
|
||||
* 对指针p处的内存进行释放(这类似于free(),只是对内存进行释放操作,至于置空指针p的操作,应交给调用方完成)
|
||||
*
|
||||
* 注:这里没有验证p的取值,调用方应当确保p在合规的范围
|
||||
*/
|
||||
void FreeBuddy(FreeList avail, WORD* p);
|
||||
|
||||
/*
|
||||
* 打印内存布局,查看当前内存的使用情况
|
||||
* 注:仅限内部测试使用
|
||||
*/
|
||||
void PrintMemoryLayout();
|
||||
|
||||
/*
|
||||
* 查找块p的伙伴
|
||||
*
|
||||
* 将一个空闲块对半分裂后,会生成的两个小空闲块,这两个小空闲块互为伙伴。
|
||||
*
|
||||
* 计算伙伴的算法为:
|
||||
* 对于起始地址为p,大小为2^k的内存块:
|
||||
* 1.若 p MOD 2^(k+1) == 0 ,则p的伙伴块的起始地址为p+2^k,
|
||||
* 2.若 p MOD 2^(k+1) == 2^k ,则p的伙伴块的起始地址为p-2^k。
|
||||
*
|
||||
* 注:仅限内部使用,用在回收算法中
|
||||
*/
|
||||
static WORD* Buddy(WORD* p);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
# 包含公共库
|
||||
include_directories(${CMAKE_SOURCE_DIR}/Status)
|
||||
|
||||
# 生成可执行文件
|
||||
add_executable(08.14 BuddySystem.h BuddySystem.c 08.14.c)
|
||||
# 链接公共库
|
||||
target_link_libraries(08.14 Scanf_lib)
|
||||
|
||||
# 记录要拷贝到*.exe目录下的资源文件
|
||||
file(GLOB TestData TestData*.txt)
|
||||
# 将资源文件拷贝到*.exe目录下,不然无法加载
|
||||
file(COPY ${TestData} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
@@ -0,0 +1,85 @@
|
||||
#include <stdio.h>
|
||||
#include "MemoryManager.h"
|
||||
|
||||
/*
|
||||
* 内存整理
|
||||
*
|
||||
* 将空闲块收集起来,链接成一条空闲块链表。
|
||||
*/
|
||||
void Algo_8_15(Space* space);
|
||||
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
Space space;
|
||||
int i;
|
||||
int a[11] = {10, 20, 30, 15, 20, 5, -1, -3, 0, 15, 10};
|
||||
WORD* p[11];
|
||||
|
||||
InitSpace(&space);
|
||||
printf("初始内存布局:\n");
|
||||
PrintMemoryLayout(space);
|
||||
|
||||
/*
|
||||
* 注:
|
||||
* 申请a[4]时,仅剩25个"字",当前容差是5,因此本次会直接分配20+5=25个"字"
|
||||
* 申请a[5]时,已经没有可用的字,所以申请失败
|
||||
* 申请a[10]时,处在容差范围内,会整块分配
|
||||
*/
|
||||
for(i = 0; i < 11; i++) {
|
||||
if(a[i] > 0) {
|
||||
printf("+ 申请 %d 个字的存储\n", a[i]);
|
||||
p[i] = AllocMemory(&space, a[i]);
|
||||
} else {
|
||||
printf("- 释放 %d 个字的存储\n", a[-a[i]]);
|
||||
FreeMemory(&space, p[-a[i]]);
|
||||
}
|
||||
|
||||
PrintMemoryLayout(space);
|
||||
|
||||
if(i == 8) {
|
||||
printf("内存整理...\n");
|
||||
Algo_8_15(&space);
|
||||
PrintMemoryLayout(space);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 内存整理
|
||||
*
|
||||
* 将空闲块收集起来,链接成一条空闲块链表。
|
||||
*/
|
||||
void Algo_8_15(Space* space) {
|
||||
WORD* p, * q;
|
||||
|
||||
space->avail = NULL;
|
||||
|
||||
q = NULL;
|
||||
|
||||
// 遍历整个堆
|
||||
for(p = space->lowbound; p < space->highbound; p += p->cellsize) {
|
||||
if(p->tag == 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 先把后继置空
|
||||
p->next = NULL;
|
||||
|
||||
// 遇到了第一个空闲块
|
||||
if(space->avail == NULL) {
|
||||
space->avail = p;
|
||||
q = p;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 如果两个空闲块地址不相邻,则进行链接
|
||||
if(q + q->cellsize != p) {
|
||||
q->next = p;
|
||||
|
||||
// 对于地址相邻的空闲块,要合并
|
||||
} else {
|
||||
q->cellsize += p->cellsize;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
# 包含公共库
|
||||
include_directories(${CMAKE_SOURCE_DIR}/Status)
|
||||
|
||||
# 生成可执行文件
|
||||
add_executable(08.15 MemoryManager.h MemoryManager.c 08.15.c)
|
||||
# 链接公共库
|
||||
target_link_libraries(08.15 Scanf_lib)
|
||||
|
||||
# 记录要拷贝到*.exe目录下的资源文件(这里拷贝了TestData.md文件)
|
||||
file(GLOB TestData TestData*)
|
||||
# 将资源文件拷贝到*.exe目录下,不然无法加载
|
||||
file(COPY ${TestData} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
@@ -0,0 +1,131 @@
|
||||
/*=======================
|
||||
* 存储管理,适用于习题8.15
|
||||
========================*/
|
||||
|
||||
#include "MemoryManager.h"
|
||||
|
||||
// 初始化一片可用的存储
|
||||
void InitSpace(Space* space) {
|
||||
space->avail = (WORD*) malloc(MAXSIZE * sizeof(WORD));
|
||||
space->avail->tag = 0;
|
||||
space->avail->cellsize = MAXSIZE;
|
||||
space->avail->next = NULL;
|
||||
|
||||
space->lowbound = space->avail;
|
||||
space->highbound = space->avail + MAXSIZE;
|
||||
}
|
||||
|
||||
// 分配大小为n的内存,并返回指向该内存的虚拟地址
|
||||
WORD* AllocMemory(Space* space, int n) {
|
||||
WORD* p, * q;
|
||||
|
||||
if(space->avail == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p = space->avail;
|
||||
q = NULL;
|
||||
|
||||
// 如果第一个空闲块不满足条件
|
||||
if(p->cellsize < n) {
|
||||
// 查找满足条件的空闲内存
|
||||
while(p != NULL && p->cellsize < n) {
|
||||
q = p;
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
|
||||
// 没有符合条件的空闲内存
|
||||
if(p == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 在容差范围内,则整块分配
|
||||
if(p->cellsize - e <= n) {
|
||||
if(q == NULL) {
|
||||
space->avail = p->next;
|
||||
} else {
|
||||
q->next = p->next;
|
||||
}
|
||||
|
||||
// 分割空闲块
|
||||
} else {
|
||||
|
||||
if(q == NULL) {
|
||||
space->avail += n;
|
||||
space->avail->tag = 0;
|
||||
space->avail->cellsize = p->cellsize - n;
|
||||
space->avail->next = p->next;
|
||||
} else {
|
||||
q->next = p + n;
|
||||
q->next->tag = 0;
|
||||
q->next->cellsize = p->cellsize - n;
|
||||
}
|
||||
|
||||
p->cellsize = n;
|
||||
}
|
||||
|
||||
// 标记为占用
|
||||
p->tag = 1;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
// 释放指针p处的内存
|
||||
void FreeMemory(Space* space, WORD* p) {
|
||||
p->tag = 0; // 简单地标记为空闲,以待后续整理
|
||||
}
|
||||
|
||||
// 打印内存布局
|
||||
void PrintMemoryLayout(Space space) {
|
||||
int i, count;
|
||||
WORD* p;
|
||||
|
||||
// 遍历所有块
|
||||
for(p = space.lowbound; p < space.highbound; p += p->cellsize) {
|
||||
if(p->tag == 0) {
|
||||
p->flag = -1; // 暂时标记为"不可用"的空闲块
|
||||
} else {
|
||||
p->flag = 1; // 标记为占用
|
||||
}
|
||||
}
|
||||
|
||||
// 遍历空闲块链表
|
||||
for(p = space.avail; p != NULL; p = p->next) {
|
||||
p->flag = 0; // 更新为"可用"的空闲块
|
||||
}
|
||||
|
||||
count = 0;
|
||||
|
||||
for(p = space.lowbound; p < space.highbound; p += p->cellsize) {
|
||||
for(i = 0; i < p->cellsize; i++) {
|
||||
switch(p->flag) {
|
||||
case -1:
|
||||
printf("△");
|
||||
break;
|
||||
case 0:
|
||||
printf("□");
|
||||
break;
|
||||
case 1:
|
||||
printf("■");
|
||||
break;
|
||||
default:
|
||||
printf("错误的标记!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
count++;
|
||||
// 每隔20个字换一下行
|
||||
if(count % 20 == 0) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(count % 20 != 0) {
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*=======================
|
||||
* 存储管理,适用于习题8.15
|
||||
========================*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef MEMORYMANAGER_H
|
||||
#define MEMORYMANAGER_H
|
||||
|
||||
|
||||
/* 宏定义 */
|
||||
#define MAXSIZE 100 // 内存总容量
|
||||
#define e 5 // 分配空间时用到的容差
|
||||
|
||||
|
||||
/*
|
||||
* 内存"字"的类型定义
|
||||
*
|
||||
* 所谓"字"是指空间分配的最小单位,它不是字节。
|
||||
* 一个"字"有多大,取决于对"字"结构是如何定义的。
|
||||
*/
|
||||
typedef struct WORD {
|
||||
int tag; // 块标志,0空闲,1占用
|
||||
int cellsize; // 当前块的大小
|
||||
struct WORD* next; // 指向下一个空闲块
|
||||
|
||||
|
||||
/*
|
||||
* 使用标记,0代表空闲,1代表占用,-1代表虽然空闲,但是不在空闲链表中。
|
||||
* 这个标记仅用来测试打印功能,并没有其它实质性的用处。
|
||||
*/
|
||||
int flag;
|
||||
} WORD;
|
||||
|
||||
// "堆"空间
|
||||
typedef struct {
|
||||
struct WORD* lowbound; // 空间下界
|
||||
struct WORD* highbound; // 空间上界
|
||||
struct WORD* avail; // 指向可用空间链表
|
||||
} Space;
|
||||
|
||||
|
||||
// 初始化一片可用的存储
|
||||
void InitSpace(Space* space);
|
||||
|
||||
// 分配大小为n的内存,并返回指向该内存的虚拟地址
|
||||
WORD* AllocMemory(Space* space, int n);
|
||||
|
||||
// 释放指针p处的内存
|
||||
void FreeMemory(Space* space, WORD* p);
|
||||
|
||||
// 打印内存布局
|
||||
void PrintMemoryLayout(Space space);
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,12 @@
|
||||
# 包含公共库
|
||||
include_directories(${CMAKE_SOURCE_DIR}/Status)
|
||||
|
||||
# 生成可执行文件
|
||||
add_executable(08.16 SqList.h SqList.c MemoryManager.h MemoryManager.c 08.16.c)
|
||||
# 链接公共库
|
||||
target_link_libraries(08.16 Scanf_lib)
|
||||
|
||||
# 记录要拷贝到*.exe目录下的资源文件(这里拷贝了TestData.md文件)
|
||||
file(GLOB TestData TestData*)
|
||||
# 将资源文件拷贝到*.exe目录下,不然无法加载
|
||||
file(COPY ${TestData} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,63 @@
|
||||
/*=======================
|
||||
* 存储管理,适用于习题8.16
|
||||
========================*/
|
||||
|
||||
#ifndef MEMORYMANAGER_H
|
||||
#define MEMORYMANAGER_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "SqList.h"
|
||||
|
||||
|
||||
#define MAXSIZE 100 // 最大内存量
|
||||
#define e 0 // 容差
|
||||
|
||||
#define BYTE sizeof(char) // 1个字节
|
||||
|
||||
|
||||
// 内存记录类型定义
|
||||
typedef struct {
|
||||
int addr; // 新地址域,存储内存块的当前最新地址,初始值是空间首地址
|
||||
int size; // 块大小
|
||||
int tag; // 标志域,指示内存是正在使用(1)还是空闲状态(0)
|
||||
|
||||
/* 存储块之间的链接关系,这与用户在虚拟地址层看到的链接关系可能并不一致 */
|
||||
int pre; // 前驱
|
||||
int next; // 后继
|
||||
|
||||
int oldAddr; // 进行存储紧缩后的旧地址
|
||||
} Record;
|
||||
|
||||
// 可用空间类型定义
|
||||
typedef struct {
|
||||
void* base; // 内存起始地址
|
||||
SqList recordList; // 内存使用记录
|
||||
int cur; // 记录空闲块的内存记录的位置,初值为1
|
||||
|
||||
/*
|
||||
* 记录虚拟地址。
|
||||
* 这其实是在模拟操作系统的行为:
|
||||
* 用户使用的地址跟硬件的实际地址可能并不一致,所以需要操作系统构造一个虚拟地址集。
|
||||
*/
|
||||
SqList ptrList;
|
||||
} Space;
|
||||
|
||||
|
||||
// 初始化一片可用的存储
|
||||
void InitSpace(Space* space);
|
||||
|
||||
// 分配大小为n的内存,并返回指向该内存的虚拟地址
|
||||
int* AllocMemory(Space* space, int n);
|
||||
|
||||
// 释放虚拟地址p处的内存
|
||||
void FreeMemory(Space* space, int* p);
|
||||
|
||||
// 将虚拟地址addr转换为底层的真实地址
|
||||
void* getPtr(Space space, const int* addr);
|
||||
|
||||
// 打印内存布局,显示格式为:首地址 块大小 标志域 | 前驱 后继 | 数据
|
||||
void PrintMemoryLayout(Space space);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,173 @@
|
||||
/*=============================
|
||||
* 线性表的顺序存储结构(顺序表)
|
||||
*
|
||||
* 包含算法: 2.3、2.4、2.5、2.6
|
||||
=============================*/
|
||||
|
||||
#include "SqList.h"
|
||||
|
||||
/*
|
||||
* ████████ 算法2.3 ████████
|
||||
*
|
||||
* 初始化
|
||||
*
|
||||
* 初始化成功则返回OK,否则返回ERROR。
|
||||
*/
|
||||
Status InitList(SqList* L) {
|
||||
// 分配指定容量的内存,如果分配失败,则返回NULL
|
||||
(*L).elem = (ElemType*) malloc(LIST_INIT_SIZE * sizeof(ElemType));
|
||||
if((*L).elem == NULL) {
|
||||
// 存储内存失败
|
||||
exit(OVERFLOW);
|
||||
}
|
||||
|
||||
(*L).length = 0; // 初始化顺序表长度为0
|
||||
(*L).listsize = LIST_INIT_SIZE; // 顺序表初始内存分配量
|
||||
|
||||
return OK; // 初始化成功
|
||||
}
|
||||
|
||||
/*
|
||||
* 计数
|
||||
*
|
||||
* 返回顺序表包含的有效元素的数量。
|
||||
*/
|
||||
int ListLength(SqList L) {
|
||||
return L.length;
|
||||
}
|
||||
|
||||
/*
|
||||
* 取值
|
||||
*
|
||||
* 获取顺序表中第i个元素,将其存储到e中。
|
||||
* 如果可以找到,返回OK,否则,返回ERROR。
|
||||
*
|
||||
*【备注】
|
||||
* 教材中i的含义是元素位置,从1开始计数,但这不符合编码的通用约定。
|
||||
* 通常,i的含义应该指索引,即从0开始计数。
|
||||
*/
|
||||
Status GetElem(SqList L, int i, ElemType* e) {
|
||||
// 因为i的含义是位置,所以其合法范围是:[1, length]
|
||||
if(i < 1 || i > L.length) {
|
||||
return ERROR; //i值不合法
|
||||
}
|
||||
|
||||
*e = L.elem[i - 1];
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* ████████ 算法2.4 ████████
|
||||
*
|
||||
* 插入
|
||||
*
|
||||
* 向顺序表第i个位置上插入e,插入成功则返回OK,否则返回ERROR。
|
||||
*
|
||||
*【备注】
|
||||
* 教材中i的含义是元素位置,从1开始计数
|
||||
*/
|
||||
Status ListInsert(SqList* L, int i, ElemType e) {
|
||||
ElemType* newbase;
|
||||
ElemType* p, * q;
|
||||
|
||||
// 确保顺序表结构存在
|
||||
if(L == NULL || (*L).elem == NULL) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// i值越界
|
||||
if(i < 1 || i > (*L).length + 1) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// 若存储空间已满,则增加新空间
|
||||
if((*L).length >= (*L).listsize) {
|
||||
// 基于现有空间扩容
|
||||
newbase = (ElemType*) realloc((*L).elem, ((*L).listsize + LISTINCREMENT) * sizeof(ElemType));
|
||||
if(newbase == NULL) {
|
||||
// 存储内存失败
|
||||
exit(OVERFLOW);
|
||||
}
|
||||
|
||||
// 新基址
|
||||
(*L).elem = newbase;
|
||||
// 存的存储空间
|
||||
(*L).listsize += LISTINCREMENT;
|
||||
}
|
||||
|
||||
// q为插入位置
|
||||
q = &(*L).elem[i - 1];
|
||||
|
||||
// 1.右移元素,腾出位置
|
||||
for(p = &(*L).elem[(*L).length - 1]; p >= q; --p) {
|
||||
*(p + 1) = *p;
|
||||
}
|
||||
|
||||
// 2.插入e
|
||||
*q = e;
|
||||
|
||||
// 3.表长增1
|
||||
(*L).length++;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* ████████ 算法2.5 ████████
|
||||
*
|
||||
* 删除
|
||||
*
|
||||
* 删除顺序表第i个位置上的元素,并将被删除元素存储到e中。
|
||||
* 删除成功则返回OK,否则返回ERROR。
|
||||
*
|
||||
*【备注】
|
||||
* 教材中i的含义是元素位置,从1开始计数
|
||||
*/
|
||||
Status ListDelete(SqList* L, int i, ElemType* e) {
|
||||
ElemType* p, * q;
|
||||
|
||||
// 确保顺序表结构存在
|
||||
if(L == NULL || (*L).elem == NULL) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// i值越界
|
||||
if(i < 1 || i > (*L).length) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// p为被删除元素的位置
|
||||
p = &(*L).elem[i - 1];
|
||||
|
||||
// 1.获取被删除元素
|
||||
*e = *p;
|
||||
|
||||
// 表尾元素位置
|
||||
q = (*L).elem + (*L).length - 1;
|
||||
|
||||
// 2.左移元素,被删除元素的位置上会有新元素进来
|
||||
for(++p; p <= q; ++p) {
|
||||
*(p - 1) = *p;
|
||||
}
|
||||
|
||||
// 3.表长减1
|
||||
(*L).length--;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* 遍历
|
||||
*
|
||||
* 用visit函数访问顺序表L
|
||||
*/
|
||||
void ListTraverse(SqList L, void(Visit)(ElemType)) {
|
||||
int i;
|
||||
|
||||
for(i = 0; i < L.length; i++) {
|
||||
Visit(L.elem[i]);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*=============================
|
||||
* 线性表的顺序存储结构(顺序表)
|
||||
*
|
||||
* 包含算法: 2.3、2.4、2.5、2.6
|
||||
=============================*/
|
||||
|
||||
#ifndef SQLIST_H
|
||||
#define SQLIST_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> // 提供malloc、realloc、free、exit原型
|
||||
#include "Status.h" //**▲01 绪论**//
|
||||
|
||||
/* 宏定义 */
|
||||
#define LIST_INIT_SIZE 100 // 顺序表存储空间的初始分配量
|
||||
#define LISTINCREMENT 10 // 顺序表存储空间的分配增量
|
||||
|
||||
|
||||
/* 顺序表元素类型定义 */
|
||||
typedef void* ElemType;
|
||||
|
||||
/*
|
||||
* 顺序表结构
|
||||
*
|
||||
* 注:elem在使用前需要先为其分配内存,且元素从elem[0]处开始存储
|
||||
*/
|
||||
typedef struct {
|
||||
ElemType* elem; // 顺序表存储空间的基址(指向顺序表所占内存的起始位置)
|
||||
int length; // 当前顺序表长度(包含多少元素)
|
||||
int listsize; // 当前分配的存储容量(可以存储多少元素)
|
||||
} SqList;
|
||||
|
||||
|
||||
/*
|
||||
* ████████ 算法2.3 ████████
|
||||
*
|
||||
* 初始化
|
||||
*
|
||||
* 初始化成功则返回OK,否则返回ERROR。
|
||||
*/
|
||||
Status InitList(SqList* L);
|
||||
|
||||
/*
|
||||
* 计数
|
||||
*
|
||||
* 返回顺序表包含的有效元素的数量。
|
||||
*/
|
||||
int ListLength(SqList L);
|
||||
|
||||
/*
|
||||
* 取值
|
||||
*
|
||||
* 获取顺序表中第i个元素,将其存储到e中。
|
||||
* 如果可以找到,返回OK,否则,返回ERROR。
|
||||
*
|
||||
*【备注】
|
||||
* 教材中i的含义是元素位置,从1开始计数,但这不符合编码的通用约定。
|
||||
* 通常,i的含义应该指索引,即从0开始计数。
|
||||
*/
|
||||
Status GetElem(SqList L, int i, ElemType* e);
|
||||
|
||||
/*
|
||||
* ████████ 算法2.4 ████████
|
||||
*
|
||||
* 插入
|
||||
*
|
||||
* 向顺序表第i个位置上插入e,插入成功则返回OK,否则返回ERROR。
|
||||
*
|
||||
*【备注】
|
||||
* 教材中i的含义是元素位置,从1开始计数
|
||||
*/
|
||||
Status ListInsert(SqList* L, int i, ElemType e);
|
||||
|
||||
/*
|
||||
* ████████ 算法2.5 ████████
|
||||
*
|
||||
* 删除
|
||||
*
|
||||
* 删除顺序表第i个位置上的元素,并将被删除元素存储到e中。
|
||||
* 删除成功则返回OK,否则返回ERROR。
|
||||
*
|
||||
*【备注】
|
||||
* 教材中i的含义是元素位置,从1开始计数
|
||||
*/
|
||||
Status ListDelete(SqList* L, int i, ElemType* e);
|
||||
|
||||
/*
|
||||
* 遍历
|
||||
*
|
||||
* 用visit函数访问顺序表L
|
||||
*/
|
||||
void ListTraverse(SqList L, void (Visit)(ElemType));
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,17 @@
|
||||
| 首地址 | 块大小 | 标志域 | 前驱指针 | 后继指针 |
|
||||
| :----: | :----: | :----: | :----: | :----: |
|
||||
| 0 | 5 | 1 | -1 | 10 |
|
||||
| 5 | 5 | 0 | -1 | -1 |
|
||||
| 10 | 5 | 1 | 15 | 40 |
|
||||
| 15 | 10 | 1 | -1 | -1 |
|
||||
| 25 | 5 | 0 | -1 | -1 |
|
||||
| 30 | 10 | 0 | -1 | -1 |
|
||||
| 40 | 5 | 1 | 45 | 65 |
|
||||
| 45 | 10 | 1 | -1 | -1 |
|
||||
| 55 | 5 | 0 | -1 | -1 |
|
||||
| 60 | 5 | 0 | -1 | -1 |
|
||||
| 65 | 5 | 1 | 85 | -1 |
|
||||
| 70 | 5 | 0 | -1 | -1 |
|
||||
| 75 | 10 | 0 | -1 | -1 |
|
||||
| 85 | 5 | 1 | 90 | -1 |
|
||||
| 90 | 10 | 1 | -1 | -1 |
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 55 KiB |
@@ -148,3 +148,9 @@ add_subdirectory(07.39)
|
||||
add_subdirectory(07.40)
|
||||
add_subdirectory(07.41)
|
||||
add_subdirectory(07.42)
|
||||
|
||||
add_subdirectory(08.11-08.12)
|
||||
add_subdirectory(08.13)
|
||||
add_subdirectory(08.14)
|
||||
add_subdirectory(08.15)
|
||||
add_subdirectory(08.16)
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
#include <stdio.h>
|
||||
#include "Status.h"
|
||||
#include "SqStack.h"
|
||||
|
||||
/* 宏定义 */
|
||||
#define MAXSIZE 200 // 内存总大小
|
||||
|
||||
|
||||
/* 空闲空间类型定义 */
|
||||
typedef struct {
|
||||
void* base; // 可用空间内存的起始地址
|
||||
int size; // 空闲空间大小(按字节计数)
|
||||
SqStack block; // 已经使用的内存块大小,先申请的内存信息先入栈
|
||||
} Space;
|
||||
|
||||
|
||||
// 初始化内存空间及内存信息栈
|
||||
void InitSpace(Space* space);
|
||||
|
||||
// 打印内存布局,查看当前内存的使用情况
|
||||
void PrintMemoryLayout(Space space);
|
||||
|
||||
// 申请大小为n的内存块,返回申请到的内存起始地址
|
||||
void* Algo_8_11(Space* space, int n);
|
||||
|
||||
// 回收内存,遵循"最后分配者最先释放"的原则
|
||||
Status Algo_8_12(Space* space);
|
||||
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
Space space;
|
||||
int s[5] = {50, 50, 150, 100, 50}; // 定义内存申请数量
|
||||
int i;
|
||||
|
||||
// 初始化内存
|
||||
InitSpace(&space);
|
||||
PrintMemoryLayout(space);
|
||||
printf("\n");
|
||||
|
||||
// 申请/释放内存
|
||||
for(i = 0; i < 5; i++) {
|
||||
printf("申请 %d 个内存后...\n", s[i]);
|
||||
Algo_8_11(&space, s[i]);
|
||||
PrintMemoryLayout(space);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// 初始化一块空闲空间
|
||||
void InitSpace(Space* space) {
|
||||
// 申请MAX字节的空间(假设总能初始化成功)
|
||||
space->base = malloc(MAXSIZE);
|
||||
space->size = MAXSIZE;
|
||||
|
||||
// 初始化内存信息栈
|
||||
InitStack(&(space->block));
|
||||
}
|
||||
|
||||
// 打印内存布局,查看当前内存的使用情况
|
||||
void PrintMemoryLayout(Space space) {
|
||||
int i;
|
||||
|
||||
for(i = 1; i <= MAXSIZE; i++) {
|
||||
if(i <= space.size) {
|
||||
printf("□");
|
||||
} else {
|
||||
printf("■");
|
||||
}
|
||||
|
||||
// 预定每隔20个换一下行
|
||||
if(i % 20 == 0) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
if(MAXSIZE % 20 != 0) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
// 申请大小为n的内存块,返回申请到的内存起始地址
|
||||
void* Algo_8_11(Space* space, int n) {
|
||||
|
||||
/*
|
||||
* 如果可用的内存数量少于申请的内存数量,
|
||||
* 则需要释放最近申请使用的内存以腾出空间。
|
||||
*/
|
||||
while(space->size < n && Algo_8_12(space) == OK) {
|
||||
// 直到空闲内存满足申请要求,或者全部占用内存已经释放,才会退出循环
|
||||
}
|
||||
|
||||
// 如果没有足够的内存可用,则返回空指针
|
||||
if(space->size < n) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 可用空间减小
|
||||
space->size -= n;
|
||||
|
||||
// 记下成功申请到的内存
|
||||
Push(&(space->block), n);
|
||||
|
||||
// 返回申请到的内存起始地址
|
||||
return space->base + space->size;
|
||||
}
|
||||
|
||||
// 回收内存,遵循"最后分配者最先释放"的原则
|
||||
Status Algo_8_12(Space* space) {
|
||||
int e;
|
||||
|
||||
// 已经没有可释放内存时,返回ERROR
|
||||
if(StackEmpty(space->block)) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// 将最后申请的内存释放掉
|
||||
Pop(&(space->block), &e);
|
||||
|
||||
// 可用空间增大
|
||||
space->size += e;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
[Project]
|
||||
FileName=08.11-08.12.dev
|
||||
Name=08.11-08.12
|
||||
Type=1
|
||||
Ver=2
|
||||
ObjFiles=
|
||||
Includes=
|
||||
Libs=
|
||||
PrivateResource=
|
||||
ResourceIncludes=
|
||||
MakeIncludes=
|
||||
Compiler=
|
||||
CppCompiler=
|
||||
Linker=
|
||||
IsCpp=0
|
||||
Icon=
|
||||
ExeOutput=
|
||||
ObjectOutput=
|
||||
LogOutput=
|
||||
LogOutputEnabled=0
|
||||
OverrideOutput=0
|
||||
OverrideOutputName=
|
||||
HostApplication=
|
||||
UseCustomMakefile=0
|
||||
CustomMakefile=
|
||||
CommandLine=
|
||||
Folders=
|
||||
IncludeVersionInfo=0
|
||||
SupportXPThemes=0
|
||||
CompilerSet=1
|
||||
CompilerSettings=0000000000000000001000000
|
||||
UnitCount=3
|
||||
|
||||
[VersionInfo]
|
||||
Major=1
|
||||
Minor=0
|
||||
Release=0
|
||||
Build=0
|
||||
LanguageID=1033
|
||||
CharsetID=1252
|
||||
CompanyName=
|
||||
FileVersion=
|
||||
FileDescription=Developed using the Dev-C++ IDE
|
||||
InternalName=
|
||||
LegalCopyright=
|
||||
LegalTrademarks=
|
||||
OriginalFilename=
|
||||
ProductName=
|
||||
ProductVersion=
|
||||
AutoIncBuildNr=0
|
||||
SyncProduct=1
|
||||
|
||||
[Unit3]
|
||||
FileName=SqStack.h
|
||||
CompileCpp=0
|
||||
Folder=
|
||||
Compile=1
|
||||
Link=1
|
||||
Priority=1000
|
||||
OverrideBuildCmd=0
|
||||
BuildCmd=
|
||||
|
||||
[Unit2]
|
||||
FileName=SqStack.cpp
|
||||
CompileCpp=0
|
||||
Folder=
|
||||
Compile=1
|
||||
Link=1
|
||||
Priority=1000
|
||||
OverrideBuildCmd=0
|
||||
BuildCmd=
|
||||
|
||||
[Unit1]
|
||||
FileName=08.11-08.12.cpp
|
||||
CompileCpp=0
|
||||
Folder=
|
||||
Compile=1
|
||||
Link=1
|
||||
Priority=1000
|
||||
OverrideBuildCmd=0
|
||||
BuildCmd=
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/*=========================
|
||||
* 栈的顺序存储结构(顺序栈)
|
||||
==========================*/
|
||||
|
||||
#include "SqStack.h" //**▲03 栈和队列**//
|
||||
|
||||
/*
|
||||
* 初始化
|
||||
*
|
||||
* 构造一个空栈。初始化成功则返回OK,否则返回ERROR。
|
||||
*/
|
||||
Status InitStack(SqStack* S) {
|
||||
if(S == NULL) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
(*S).base = (SElemType*) malloc(STACK_INIT_SIZE * sizeof(SElemType));
|
||||
if((*S).base == NULL) {
|
||||
exit(OVERFLOW);
|
||||
}
|
||||
|
||||
(*S).top = (*S).base;
|
||||
(*S).stacksize = STACK_INIT_SIZE;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* 判空
|
||||
*
|
||||
* 判断顺序栈中是否包含有效数据。
|
||||
*
|
||||
* 返回值:
|
||||
* TRUE : 顺序栈为空
|
||||
* FALSE: 顺序栈不为空
|
||||
*/
|
||||
Status StackEmpty(SqStack S) {
|
||||
if(S.top == S.base) {
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 入栈
|
||||
*
|
||||
* 将元素e压入到栈顶。
|
||||
*/
|
||||
Status Push(SqStack* S, SElemType e) {
|
||||
if(S == NULL || (*S).base == NULL) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// 栈满时,追加存储空间
|
||||
if((*S).top - (*S).base >= (*S).stacksize) {
|
||||
(*S).base = (SElemType*) realloc((*S).base, ((*S).stacksize + STACKINCREMENT) * sizeof(SElemType));
|
||||
if((*S).base == NULL) {
|
||||
exit(OVERFLOW); // 存储分配失败
|
||||
}
|
||||
|
||||
(*S).top = (*S).base + (*S).stacksize;
|
||||
(*S).stacksize += STACKINCREMENT;
|
||||
}
|
||||
|
||||
// 进栈先赋值,栈顶指针再自增
|
||||
*(S->top++) = e;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* 出栈
|
||||
*
|
||||
* 将栈顶元素弹出,并用e接收。
|
||||
*/
|
||||
Status Pop(SqStack* S, SElemType* e) {
|
||||
if(S == NULL || (*S).base == NULL) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
if((*S).top == (*S).base) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// 出栈栈顶指针先递减,再赋值
|
||||
*e = *(--(*S).top);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*=========================
|
||||
* 栈的顺序存储结构(顺序栈)
|
||||
==========================*/
|
||||
|
||||
#ifndef SQSTACK_H
|
||||
#define SQSTACK_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> // 提供malloc、realloc、free、exit原型
|
||||
#include "Status.h" //**▲01 绪论**//
|
||||
|
||||
/* 宏定义 */
|
||||
#define STACK_INIT_SIZE 100 // 顺序栈存储空间的初始分配量
|
||||
#define STACKINCREMENT 10 // 顺序栈存储空间的分配增量
|
||||
|
||||
/* 顺序栈元素类型定义 */
|
||||
typedef int SElemType;
|
||||
|
||||
// 顺序栈元素结构
|
||||
typedef struct {
|
||||
SElemType* base; // 栈底指针
|
||||
SElemType* top; // 栈顶指针
|
||||
int stacksize; // 当前已分配的存储空间,以元素为单位
|
||||
} SqStack;
|
||||
|
||||
|
||||
/*
|
||||
* 初始化
|
||||
*
|
||||
* 构造一个空栈。初始化成功则返回OK,否则返回ERROR。
|
||||
*/
|
||||
Status InitStack(SqStack* S);
|
||||
|
||||
/*
|
||||
* 判空
|
||||
*
|
||||
* 判断顺序栈中是否包含有效数据。
|
||||
*
|
||||
* 返回值:
|
||||
* TRUE : 顺序栈为空
|
||||
* FALSE: 顺序栈不为空
|
||||
*/
|
||||
Status StackEmpty(SqStack S);
|
||||
|
||||
/*
|
||||
* 入栈
|
||||
*
|
||||
* 将元素e压入到栈顶。
|
||||
*/
|
||||
Status Push(SqStack* S, SElemType e);
|
||||
|
||||
/*
|
||||
* 出栈
|
||||
*
|
||||
* 将栈顶元素弹出,并用e接收。
|
||||
*/
|
||||
Status Pop(SqStack* S, SElemType* e);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
#include <stdio.h>
|
||||
#include "BoundaryTagMethod.h" //**▲08 动态存储管理**//
|
||||
|
||||
/*
|
||||
* 边界标识法的内存回收算法
|
||||
*
|
||||
* 对指针p处的内存进行释放
|
||||
*/
|
||||
void Algo_8_13(Space* pav, Space p);
|
||||
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
Space pav;
|
||||
Space p[12]; // 记录申请到的内存的指针
|
||||
int s[12] = {10, 20, 30, 50, 5, 15, 10, 5, 15, 15, 2, 20}; // 申请的空间大小
|
||||
int i = 0;
|
||||
|
||||
printf("████████ InitSpace \n");
|
||||
{
|
||||
int max = 200; // 初值建议为20的倍数,目的是打印出来可以对齐
|
||||
|
||||
printf("初始化包含 %d 个\"字\"的内存块后,当前内存布局为:\n", max);
|
||||
pav = InitSpace(max);
|
||||
PrintMemoryLayout();
|
||||
printf("\n");
|
||||
}
|
||||
PressEnterToContinue(debug);
|
||||
|
||||
printf("████████ AllocBoundTag \n");
|
||||
{
|
||||
for(i = 0; i < 12; i++) {
|
||||
printf("████ %2d> 申请 %d 个\"字\"的内存后,当前内存布局为:\n", i + 1, s[i]);
|
||||
p[i] = AllocBoundTag(&pav, s[i]);
|
||||
PrintMemoryLayout();
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
PressEnterToContinue(debug);
|
||||
|
||||
printf("████████ FreeBoundTag \n");
|
||||
{
|
||||
// 定义一个指针回收顺序
|
||||
int a[10] = {7, 3, 10, 6, 8, 5, 11, 1, 0, 4};
|
||||
|
||||
for(i = 0; i < 10; i++) {
|
||||
printf("回收 p%d 指向的内存...\n", a[i] + 1);
|
||||
Algo_8_13(&pav, p[a[i]]);
|
||||
PrintMemoryLayout();
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
PressEnterToContinue(debug);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 边界标识法的内存回收算法
|
||||
*
|
||||
* 对指针p处的内存进行释放
|
||||
*/
|
||||
void Algo_8_13(Space* pav, Space p) {
|
||||
FreeBoundTag(pav, p);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
[Project]
|
||||
FileName=08.13.dev
|
||||
Name=08.13
|
||||
Type=1
|
||||
Ver=2
|
||||
ObjFiles=
|
||||
Includes=
|
||||
Libs=
|
||||
PrivateResource=
|
||||
ResourceIncludes=
|
||||
MakeIncludes=
|
||||
Compiler=
|
||||
CppCompiler=
|
||||
Linker=
|
||||
IsCpp=0
|
||||
Icon=
|
||||
ExeOutput=
|
||||
ObjectOutput=
|
||||
LogOutput=
|
||||
LogOutputEnabled=0
|
||||
OverrideOutput=0
|
||||
OverrideOutputName=
|
||||
HostApplication=
|
||||
UseCustomMakefile=0
|
||||
CustomMakefile=
|
||||
CommandLine=
|
||||
Folders=
|
||||
IncludeVersionInfo=0
|
||||
SupportXPThemes=0
|
||||
CompilerSet=1
|
||||
CompilerSettings=0000000000000000001000000
|
||||
UnitCount=3
|
||||
|
||||
[VersionInfo]
|
||||
Major=1
|
||||
Minor=0
|
||||
Release=0
|
||||
Build=0
|
||||
LanguageID=1033
|
||||
CharsetID=1252
|
||||
CompanyName=
|
||||
FileVersion=
|
||||
FileDescription=Developed using the Dev-C++ IDE
|
||||
InternalName=
|
||||
LegalCopyright=
|
||||
LegalTrademarks=
|
||||
OriginalFilename=
|
||||
ProductName=
|
||||
ProductVersion=
|
||||
AutoIncBuildNr=0
|
||||
SyncProduct=1
|
||||
|
||||
[Unit1]
|
||||
FileName=08.13.cpp
|
||||
CompileCpp=0
|
||||
Folder=
|
||||
Compile=1
|
||||
Link=1
|
||||
Priority=1000
|
||||
OverrideBuildCmd=0
|
||||
BuildCmd=
|
||||
|
||||
[Unit2]
|
||||
FileName=BoundaryTagMethod.cpp
|
||||
CompileCpp=0
|
||||
Folder=
|
||||
Compile=1
|
||||
Link=1
|
||||
Priority=1000
|
||||
OverrideBuildCmd=0
|
||||
BuildCmd=
|
||||
|
||||
[Unit3]
|
||||
FileName=BoundaryTagMethod.h
|
||||
CompileCpp=0
|
||||
Folder=
|
||||
Compile=1
|
||||
Link=1
|
||||
Priority=1000
|
||||
OverrideBuildCmd=0
|
||||
BuildCmd=
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,97 @@
|
||||
/*==============
|
||||
* 边界标识法
|
||||
*
|
||||
* 包含算法: 8.1
|
||||
===============*/
|
||||
|
||||
#ifndef BOUNDARYTAGMETHOD_H
|
||||
#define BOUNDARYTAGMETHOD_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "Status.h" //**▲01 绪论**//
|
||||
|
||||
/* 宏定义 */
|
||||
#define e 5 // 分配空间时用到的容差
|
||||
#define FootLoc(p) p+(p->size)-1 // 将p指针定位到p所指内存块的底部
|
||||
|
||||
|
||||
/*
|
||||
* 内存"字"的类型定义
|
||||
*
|
||||
* 所谓"字"是指空间分配的最小单位,它不是字节。
|
||||
* 一个"字"有多大,取决于对"字"结构是如何定义的。
|
||||
*/
|
||||
typedef struct WORD {
|
||||
|
||||
/*
|
||||
* 注:
|
||||
* 教材中将llink和uplink封装在了一个联合体中,个人感觉这个封装有些鸡肋。
|
||||
* 一方面,head和foot的公共部分其实只有tag,如果真想用联合体,那么应当把size和rlink也封装起来。
|
||||
* 另一方面,这个封装节省的空间很有限,而且直接影响了代码的可读性。
|
||||
* 这里只是教学代码,而不是真实的系统代码,所以空间考虑在其次,原理展示为首要任务。
|
||||
* 此外,教材中的伪码中也并没有考虑这个联合体,而是直接进行操作的。
|
||||
* 综上所述,这里去除了教材中的联合体结构。
|
||||
* 如想观察带有联合体的写法,可以参考CFree分支的代码。
|
||||
*/
|
||||
|
||||
int tag; // 块标志,0空闲,1占用,头部和尾部均有
|
||||
|
||||
struct WORD* llink; // 头部域,指向前驱结点
|
||||
struct WORD* rlink; // 头部域,指向后继结点
|
||||
int size; // 头部域,块大小
|
||||
|
||||
struct WORD* uplink; // 底部域,指向本结点头部
|
||||
} WORD;
|
||||
|
||||
typedef WORD* Space; // Space:指向可利用空间的指针类型
|
||||
|
||||
|
||||
/*
|
||||
* 初始化一块大小为n个字的内存,并返回指向该内存的起点的指针
|
||||
* 注:返回的初始内存已经包含了head和foot。
|
||||
*/
|
||||
Space InitSpace(int n);
|
||||
|
||||
/*
|
||||
* ████████ 算法8.1 ████████
|
||||
*
|
||||
* 边界标识法的内存分配算法
|
||||
*
|
||||
* 从空间pav中申请一块大小至少为n的空间,并返回指向申请到的空间的指针。如果分配失败,则返回NULL。
|
||||
* 为了使分配后的剩余块尽量均匀分布,每次分配完之后都要把空间指针pav向前移动,具体描述参见教材。
|
||||
*
|
||||
* 注:
|
||||
* 1.这里采用首次拟合法,即一遇到满足条件的内存块就进行分配操作。
|
||||
* 2.为了避免空间碎片化过快,这里增加了一个容差e,具体含义参考教材描述。
|
||||
* 3.这里申请分配n个字的空间,指的是已经完成换算的空间。
|
||||
* 比如用户想要容量为10个字的空间,但每个空间又包含head和foot这两个字存储空间使用信息,
|
||||
* 因此实际上分配的空间大小应为12个字,这个"12"就是n的含义。
|
||||
* 教材中提到"head和foot在分配时忽略不计",这样是为了伪码书写的方便。实际写代码时,这两个空间是不能忽略的。
|
||||
* 但是如果按照上面的描述,把n解释为已经换算后空间,而不是用户原始申请的空间,
|
||||
* 那么既满足了没有忽略空间,又满足了在书面效果上,跟教材伪码统一,可谓两全其美。
|
||||
*/
|
||||
Space AllocBoundTag(Space* pav, int n);
|
||||
|
||||
/*
|
||||
* 边界标识法的内存回收算法
|
||||
*
|
||||
* 对指针p处的内存进行释放
|
||||
*/
|
||||
void FreeBoundTag(Space* pav, Space p);
|
||||
|
||||
/*
|
||||
* 打印内存布局,查看当前内存的使用情况
|
||||
* 注:仅限内部测试使用
|
||||
*/
|
||||
void PrintMemoryLayout();
|
||||
|
||||
/*
|
||||
* 计算可用的空闲空间容量
|
||||
*
|
||||
* 注:仅限内部使用,用在日志打印中
|
||||
*/
|
||||
static int AvailableSpace(Space pav);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
#include <stdio.h>
|
||||
#include "BuddySystem.h" //**▲08 动态存储管理**//
|
||||
|
||||
/*
|
||||
* 伙伴系统的内存回收算法
|
||||
*
|
||||
* 对指针p处的内存进行释放(这类似于free(),只是对内存进行释放操作,至于置空指针p的操作,应交给调用方完成)
|
||||
*
|
||||
* 注:这里没有验证p的取值,调用方应当确保p在合规的范围
|
||||
*/
|
||||
void Algo_8_14(FreeList avail, WORD* p);
|
||||
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
FreeList avail;
|
||||
WORD* p[8]; // 记录申请到的内存的指针
|
||||
int s[8] = {4, 5, 6, 7, 1, 5, 3, 9}; // 申请的空间大小
|
||||
int i;
|
||||
|
||||
printf("████████ InitSpace \n");
|
||||
{
|
||||
printf("初始化一个内存块...\n");
|
||||
InitSpace(avail);
|
||||
PrintMemoryLayout();
|
||||
printf("\n");
|
||||
}
|
||||
PressEnterToContinue(debug);
|
||||
|
||||
printf("████████ AllocBuddy \n");
|
||||
{
|
||||
for(i = 0; i < 8; i++) {
|
||||
printf("申请大小为 %d 个字的内存块...\n", s[i]);
|
||||
p[i] = AllocBuddy(avail, s[i]);
|
||||
PrintMemoryLayout();
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
PressEnterToContinue(debug);
|
||||
|
||||
printf("████████ FreeBuddy \n");
|
||||
{
|
||||
// 定义一个指针回收顺序
|
||||
int a[8] = {2, 0, 5, 7, 1, 4, 3, 6};
|
||||
|
||||
for(i = 0; i < 8; i++) {
|
||||
Algo_8_14(avail, p[a[i]]);
|
||||
PrintMemoryLayout();
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
PressEnterToContinue(debug);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 伙伴系统的内存回收算法
|
||||
*
|
||||
* 对指针p处的内存进行释放(这类似于free(),只是对内存进行释放操作,至于置空指针p的操作,应交给调用方完成)
|
||||
*
|
||||
* 注:这里没有验证p的取值,调用方应当确保p在合规的范围
|
||||
*/
|
||||
void Algo_8_14(FreeList avail, WORD* p) {
|
||||
FreeBuddy(avail, p);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
[Project]
|
||||
FileName=08.14.dev
|
||||
Name=08.14
|
||||
Type=1
|
||||
Ver=2
|
||||
ObjFiles=
|
||||
Includes=
|
||||
Libs=
|
||||
PrivateResource=
|
||||
ResourceIncludes=
|
||||
MakeIncludes=
|
||||
Compiler=
|
||||
CppCompiler=
|
||||
Linker=
|
||||
IsCpp=0
|
||||
Icon=
|
||||
ExeOutput=
|
||||
ObjectOutput=
|
||||
LogOutput=
|
||||
LogOutputEnabled=0
|
||||
OverrideOutput=0
|
||||
OverrideOutputName=
|
||||
HostApplication=
|
||||
UseCustomMakefile=0
|
||||
CustomMakefile=
|
||||
CommandLine=
|
||||
Folders=
|
||||
IncludeVersionInfo=0
|
||||
SupportXPThemes=0
|
||||
CompilerSet=1
|
||||
CompilerSettings=0000000000000000001000000
|
||||
UnitCount=3
|
||||
|
||||
[VersionInfo]
|
||||
Major=1
|
||||
Minor=0
|
||||
Release=0
|
||||
Build=0
|
||||
LanguageID=1033
|
||||
CharsetID=1252
|
||||
CompanyName=
|
||||
FileVersion=
|
||||
FileDescription=Developed using the Dev-C++ IDE
|
||||
InternalName=
|
||||
LegalCopyright=
|
||||
LegalTrademarks=
|
||||
OriginalFilename=
|
||||
ProductName=
|
||||
ProductVersion=
|
||||
AutoIncBuildNr=0
|
||||
SyncProduct=1
|
||||
|
||||
[Unit1]
|
||||
FileName=08.14.cpp
|
||||
CompileCpp=0
|
||||
Folder=
|
||||
Compile=1
|
||||
Link=1
|
||||
Priority=1000
|
||||
OverrideBuildCmd=0
|
||||
BuildCmd=
|
||||
|
||||
[Unit2]
|
||||
FileName=BuddySystem.cpp
|
||||
CompileCpp=0
|
||||
Folder=
|
||||
Compile=1
|
||||
Link=1
|
||||
Priority=1000
|
||||
OverrideBuildCmd=0
|
||||
BuildCmd=
|
||||
|
||||
[Unit3]
|
||||
FileName=BuddySystem.h
|
||||
CompileCpp=0
|
||||
Folder=
|
||||
Compile=1
|
||||
Link=1
|
||||
Priority=1000
|
||||
OverrideBuildCmd=0
|
||||
BuildCmd=
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,90 @@
|
||||
/*==============
|
||||
* 伙伴系统
|
||||
*
|
||||
* 包含算法: 8.2
|
||||
===============*/
|
||||
|
||||
#ifndef BUDDYSYSTEM_H
|
||||
#define BUDDYSYSTEM_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include "Status.h" //**▲01 绪论**//
|
||||
|
||||
/* 宏定义 */
|
||||
#define M 6 // 假设总空间大小为2^M个字,子表个数为M+1
|
||||
|
||||
|
||||
/*
|
||||
* 内存"字"的类型定义
|
||||
*
|
||||
* 所谓"字"是指空间分配的最小单位,它不是字节。
|
||||
* 一个"字"有多大,取决于对"字"结构是如何定义的。
|
||||
*/
|
||||
typedef struct WORD {
|
||||
struct WORD* llink; // 头部域的前驱指针
|
||||
struct WORD* rlink; // 头部域的后继指针
|
||||
int tag; // 头部域的块标志,0:空闲,1:占用
|
||||
int kval; // 指示块的大小,比如其值为K时,表示该块的大小为2^K
|
||||
} WORD;
|
||||
|
||||
// 表头向量类型
|
||||
typedef struct HeadNode {
|
||||
int nodesize; // 该链表的空闲块的大小
|
||||
WORD* first; // 该链表的表头指针
|
||||
} FreeList[M + 1];
|
||||
|
||||
|
||||
/*
|
||||
* 初始化一块大小为2^M个字的内存,并返回指向该内存的起点的指针
|
||||
* 注:返回的初始内存已经包含了head。
|
||||
*/
|
||||
void InitSpace(FreeList avail);
|
||||
|
||||
/*
|
||||
* ████████ 算法8.2 ████████
|
||||
*
|
||||
* 伙伴系统的内存分配算法
|
||||
*
|
||||
* 从空间avail中申请一块大小至少为n(原始值)的空间,并返回指向申请到的空间的指针。如果分配失败,则返回NULL。
|
||||
*
|
||||
* 注:
|
||||
* 1.这里采用首次拟合法,即一遇到满足条件的内存块就进行分配操作。
|
||||
* 2.这里申请分配n个字的空间,指的是用户申请的原始空间。
|
||||
* 实际在申请时,还要考虑到每个块前面有1个字的head信息,即经过换算后,实际需要申请(n+1)个字。
|
||||
* 这里的n与算法8.1里面的n含义正好相反,需要注意。
|
||||
*/
|
||||
WORD* AllocBuddy(FreeList avail, int n);
|
||||
|
||||
/*
|
||||
* 伙伴系统的内存回收算法
|
||||
*
|
||||
* 对指针p处的内存进行释放(这类似于free(),只是对内存进行释放操作,至于置空指针p的操作,应交给调用方完成)
|
||||
*
|
||||
* 注:这里没有验证p的取值,调用方应当确保p在合规的范围
|
||||
*/
|
||||
void FreeBuddy(FreeList avail, WORD* p);
|
||||
|
||||
/*
|
||||
* 打印内存布局,查看当前内存的使用情况
|
||||
* 注:仅限内部测试使用
|
||||
*/
|
||||
void PrintMemoryLayout();
|
||||
|
||||
/*
|
||||
* 查找块p的伙伴
|
||||
*
|
||||
* 将一个空闲块对半分裂后,会生成的两个小空闲块,这两个小空闲块互为伙伴。
|
||||
*
|
||||
* 计算伙伴的算法为:
|
||||
* 对于起始地址为p,大小为2^k的内存块:
|
||||
* 1.若 p MOD 2^(k+1) == 0 ,则p的伙伴块的起始地址为p+2^k,
|
||||
* 2.若 p MOD 2^(k+1) == 2^k ,则p的伙伴块的起始地址为p-2^k。
|
||||
*
|
||||
* 注:仅限内部使用,用在回收算法中
|
||||
*/
|
||||
static WORD* Buddy(WORD* p);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
#include <stdio.h>
|
||||
#include "MemoryManager.h"
|
||||
|
||||
/*
|
||||
* 内存整理
|
||||
*
|
||||
* 将空闲块收集起来,链接成一条空闲块链表。
|
||||
*/
|
||||
void Algo_8_15(Space* space);
|
||||
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
Space space;
|
||||
int i;
|
||||
int a[11] = {10, 20, 30, 15, 20, 5, -1, -3, 0, 15, 10};
|
||||
WORD* p[11];
|
||||
|
||||
InitSpace(&space);
|
||||
printf("初始内存布局:\n");
|
||||
PrintMemoryLayout(space);
|
||||
|
||||
/*
|
||||
* 注:
|
||||
* 申请a[4]时,仅剩25个"字",当前容差是5,因此本次会直接分配20+5=25个"字"
|
||||
* 申请a[5]时,已经没有可用的字,所以申请失败
|
||||
* 申请a[10]时,处在容差范围内,会整块分配
|
||||
*/
|
||||
for(i = 0; i < 11; i++) {
|
||||
if(a[i] > 0) {
|
||||
printf("+ 申请 %d 个字的存储\n", a[i]);
|
||||
p[i] = AllocMemory(&space, a[i]);
|
||||
} else {
|
||||
printf("- 释放 %d 个字的存储\n", a[-a[i]]);
|
||||
FreeMemory(&space, p[-a[i]]);
|
||||
}
|
||||
|
||||
PrintMemoryLayout(space);
|
||||
|
||||
if(i == 8) {
|
||||
printf("内存整理...\n");
|
||||
Algo_8_15(&space);
|
||||
PrintMemoryLayout(space);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 内存整理
|
||||
*
|
||||
* 将空闲块收集起来,链接成一条空闲块链表。
|
||||
*/
|
||||
void Algo_8_15(Space* space) {
|
||||
WORD* p, * q;
|
||||
|
||||
space->avail = NULL;
|
||||
|
||||
q = NULL;
|
||||
|
||||
// 遍历整个堆
|
||||
for(p = space->lowbound; p < space->highbound; p += p->cellsize) {
|
||||
if(p->tag == 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 先把后继置空
|
||||
p->next = NULL;
|
||||
|
||||
// 遇到了第一个空闲块
|
||||
if(space->avail == NULL) {
|
||||
space->avail = p;
|
||||
q = p;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 如果两个空闲块地址不相邻,则进行链接
|
||||
if(q + q->cellsize != p) {
|
||||
q->next = p;
|
||||
|
||||
// 对于地址相邻的空闲块,要合并
|
||||
} else {
|
||||
q->cellsize += p->cellsize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
[Project]
|
||||
FileName=08.15.dev
|
||||
Name=08.15
|
||||
Type=1
|
||||
Ver=2
|
||||
ObjFiles=
|
||||
Includes=
|
||||
Libs=
|
||||
PrivateResource=
|
||||
ResourceIncludes=
|
||||
MakeIncludes=
|
||||
Compiler=
|
||||
CppCompiler=
|
||||
Linker=
|
||||
IsCpp=0
|
||||
Icon=
|
||||
ExeOutput=
|
||||
ObjectOutput=
|
||||
LogOutput=
|
||||
LogOutputEnabled=0
|
||||
OverrideOutput=0
|
||||
OverrideOutputName=
|
||||
HostApplication=
|
||||
UseCustomMakefile=0
|
||||
CustomMakefile=
|
||||
CommandLine=
|
||||
Folders=
|
||||
IncludeVersionInfo=0
|
||||
SupportXPThemes=0
|
||||
CompilerSet=1
|
||||
CompilerSettings=0000000000000000001000000
|
||||
UnitCount=3
|
||||
|
||||
[VersionInfo]
|
||||
Major=1
|
||||
Minor=0
|
||||
Release=0
|
||||
Build=0
|
||||
LanguageID=1033
|
||||
CharsetID=1252
|
||||
CompanyName=
|
||||
FileVersion=
|
||||
FileDescription=Developed using the Dev-C++ IDE
|
||||
InternalName=
|
||||
LegalCopyright=
|
||||
LegalTrademarks=
|
||||
OriginalFilename=
|
||||
ProductName=
|
||||
ProductVersion=
|
||||
AutoIncBuildNr=0
|
||||
SyncProduct=1
|
||||
|
||||
[Unit1]
|
||||
FileName=08.15.cpp
|
||||
CompileCpp=0
|
||||
Folder=
|
||||
Compile=1
|
||||
Link=1
|
||||
Priority=1000
|
||||
OverrideBuildCmd=0
|
||||
BuildCmd=
|
||||
|
||||
[Unit2]
|
||||
FileName=MemoryManager.cpp
|
||||
CompileCpp=0
|
||||
Folder=
|
||||
Compile=1
|
||||
Link=1
|
||||
Priority=1000
|
||||
OverrideBuildCmd=0
|
||||
BuildCmd=
|
||||
|
||||
[Unit3]
|
||||
FileName=MemoryManager.h
|
||||
CompileCpp=0
|
||||
Folder=
|
||||
Compile=1
|
||||
Link=1
|
||||
Priority=1000
|
||||
OverrideBuildCmd=0
|
||||
BuildCmd=
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
/*=======================
|
||||
* 存储管理,适用于习题8.15
|
||||
========================*/
|
||||
|
||||
#include "MemoryManager.h"
|
||||
|
||||
// 初始化一片可用的存储
|
||||
void InitSpace(Space* space) {
|
||||
space->avail = (WORD*) malloc(MAXSIZE * sizeof(WORD));
|
||||
space->avail->tag = 0;
|
||||
space->avail->cellsize = MAXSIZE;
|
||||
space->avail->next = NULL;
|
||||
|
||||
space->lowbound = space->avail;
|
||||
space->highbound = space->avail + MAXSIZE;
|
||||
}
|
||||
|
||||
// 分配大小为n的内存,并返回指向该内存的虚拟地址
|
||||
WORD* AllocMemory(Space* space, int n) {
|
||||
WORD* p, * q;
|
||||
|
||||
if(space->avail == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p = space->avail;
|
||||
q = NULL;
|
||||
|
||||
// 如果第一个空闲块不满足条件
|
||||
if(p->cellsize < n) {
|
||||
// 查找满足条件的空闲内存
|
||||
while(p != NULL && p->cellsize < n) {
|
||||
q = p;
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
|
||||
// 没有符合条件的空闲内存
|
||||
if(p == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 在容差范围内,则整块分配
|
||||
if(p->cellsize - e <= n) {
|
||||
if(q == NULL) {
|
||||
space->avail = p->next;
|
||||
} else {
|
||||
q->next = p->next;
|
||||
}
|
||||
|
||||
// 分割空闲块
|
||||
} else {
|
||||
|
||||
if(q == NULL) {
|
||||
space->avail += n;
|
||||
space->avail->tag = 0;
|
||||
space->avail->cellsize = p->cellsize - n;
|
||||
space->avail->next = p->next;
|
||||
} else {
|
||||
q->next = p + n;
|
||||
q->next->tag = 0;
|
||||
q->next->cellsize = p->cellsize - n;
|
||||
}
|
||||
|
||||
p->cellsize = n;
|
||||
}
|
||||
|
||||
// 标记为占用
|
||||
p->tag = 1;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
// 释放指针p处的内存
|
||||
void FreeMemory(Space* space, WORD* p) {
|
||||
p->tag = 0; // 简单地标记为空闲,以待后续整理
|
||||
}
|
||||
|
||||
// 打印内存布局
|
||||
void PrintMemoryLayout(Space space) {
|
||||
int i, count;
|
||||
WORD* p;
|
||||
|
||||
// 遍历所有块
|
||||
for(p = space.lowbound; p < space.highbound; p += p->cellsize) {
|
||||
if(p->tag == 0) {
|
||||
p->flag = -1; // 暂时标记为"不可用"的空闲块
|
||||
} else {
|
||||
p->flag = 1; // 标记为占用
|
||||
}
|
||||
}
|
||||
|
||||
// 遍历空闲块链表
|
||||
for(p = space.avail; p != NULL; p = p->next) {
|
||||
p->flag = 0; // 更新为"可用"的空闲块
|
||||
}
|
||||
|
||||
count = 0;
|
||||
|
||||
for(p = space.lowbound; p < space.highbound; p += p->cellsize) {
|
||||
for(i = 0; i < p->cellsize; i++) {
|
||||
switch(p->flag) {
|
||||
case -1:
|
||||
printf("△");
|
||||
break;
|
||||
case 0:
|
||||
printf("□");
|
||||
break;
|
||||
case 1:
|
||||
printf("■");
|
||||
break;
|
||||
default:
|
||||
printf("错误的标记!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
count++;
|
||||
// 每隔20个字换一下行
|
||||
if(count % 20 == 0) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(count % 20 != 0) {
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*=======================
|
||||
* 存储管理,适用于习题8.15
|
||||
========================*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef MEMORYMANAGER_H
|
||||
#define MEMORYMANAGER_H
|
||||
|
||||
|
||||
/* 宏定义 */
|
||||
#define MAXSIZE 100 // 内存总容量
|
||||
#define e 5 // 分配空间时用到的容差
|
||||
|
||||
|
||||
/*
|
||||
* 内存"字"的类型定义
|
||||
*
|
||||
* 所谓"字"是指空间分配的最小单位,它不是字节。
|
||||
* 一个"字"有多大,取决于对"字"结构是如何定义的。
|
||||
*/
|
||||
typedef struct WORD {
|
||||
int tag; // 块标志,0空闲,1占用
|
||||
int cellsize; // 当前块的大小
|
||||
struct WORD* next; // 指向下一个空闲块
|
||||
|
||||
|
||||
/*
|
||||
* 使用标记,0代表空闲,1代表占用,-1代表虽然空闲,但是不在空闲链表中。
|
||||
* 这个标记仅用来测试打印功能,并没有其它实质性的用处。
|
||||
*/
|
||||
int flag;
|
||||
} WORD;
|
||||
|
||||
// "堆"空间
|
||||
typedef struct {
|
||||
struct WORD* lowbound; // 空间下界
|
||||
struct WORD* highbound; // 空间上界
|
||||
struct WORD* avail; // 指向可用空间链表
|
||||
} Space;
|
||||
|
||||
|
||||
// 初始化一片可用的存储
|
||||
void InitSpace(Space* space);
|
||||
|
||||
// 分配大小为n的内存,并返回指向该内存的虚拟地址
|
||||
WORD* AllocMemory(Space* space, int n);
|
||||
|
||||
// 释放指针p处的内存
|
||||
void FreeMemory(Space* space, WORD* p);
|
||||
|
||||
// 打印内存布局
|
||||
void PrintMemoryLayout(Space space);
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,111 @@
|
||||
[Project]
|
||||
FileName=08.16.dev
|
||||
Name=08.16
|
||||
Type=1
|
||||
Ver=2
|
||||
ObjFiles=
|
||||
Includes=
|
||||
Libs=
|
||||
PrivateResource=
|
||||
ResourceIncludes=
|
||||
MakeIncludes=
|
||||
Compiler=
|
||||
CppCompiler=
|
||||
Linker=
|
||||
IsCpp=0
|
||||
Icon=
|
||||
ExeOutput=
|
||||
ObjectOutput=
|
||||
LogOutput=
|
||||
LogOutputEnabled=0
|
||||
OverrideOutput=0
|
||||
OverrideOutputName=
|
||||
HostApplication=
|
||||
UseCustomMakefile=0
|
||||
CustomMakefile=
|
||||
CommandLine=
|
||||
Folders=
|
||||
IncludeVersionInfo=0
|
||||
SupportXPThemes=0
|
||||
CompilerSet=1
|
||||
CompilerSettings=0000000000000000001000000
|
||||
UnitCount=6
|
||||
|
||||
[VersionInfo]
|
||||
Major=1
|
||||
Minor=0
|
||||
Release=0
|
||||
Build=0
|
||||
LanguageID=1033
|
||||
CharsetID=1252
|
||||
CompanyName=
|
||||
FileVersion=
|
||||
FileDescription=Developed using the Dev-C++ IDE
|
||||
InternalName=
|
||||
LegalCopyright=
|
||||
LegalTrademarks=
|
||||
OriginalFilename=
|
||||
ProductName=
|
||||
ProductVersion=
|
||||
AutoIncBuildNr=0
|
||||
SyncProduct=1
|
||||
|
||||
[Unit1]
|
||||
FileName=08.16.cpp
|
||||
CompileCpp=0
|
||||
Folder=
|
||||
Compile=1
|
||||
Link=1
|
||||
Priority=1000
|
||||
OverrideBuildCmd=0
|
||||
BuildCmd=
|
||||
|
||||
[Unit2]
|
||||
FileName=MemoryManager.cpp
|
||||
CompileCpp=0
|
||||
Folder=
|
||||
Compile=1
|
||||
Link=1
|
||||
Priority=1000
|
||||
OverrideBuildCmd=0
|
||||
BuildCmd=
|
||||
|
||||
[Unit3]
|
||||
FileName=MemoryManager.h
|
||||
CompileCpp=0
|
||||
Folder=
|
||||
Compile=1
|
||||
Link=1
|
||||
Priority=1000
|
||||
OverrideBuildCmd=0
|
||||
BuildCmd=
|
||||
|
||||
[Unit4]
|
||||
FileName=SqList.cpp
|
||||
CompileCpp=0
|
||||
Folder=
|
||||
Compile=1
|
||||
Link=1
|
||||
Priority=1000
|
||||
OverrideBuildCmd=0
|
||||
BuildCmd=
|
||||
|
||||
[Unit5]
|
||||
FileName=SqList.h
|
||||
CompileCpp=0
|
||||
Folder=
|
||||
Compile=1
|
||||
Link=1
|
||||
Priority=1000
|
||||
OverrideBuildCmd=0
|
||||
BuildCmd=
|
||||
|
||||
[Unit6]
|
||||
FileName=TestData_8_10.md
|
||||
Folder=
|
||||
Compile=0
|
||||
Link=0
|
||||
Priority=1000
|
||||
OverrideBuildCmd=0
|
||||
BuildCmd=
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,64 @@
|
||||
/*=======================
|
||||
* 存储管理,适用于习题8.16
|
||||
========================*/
|
||||
|
||||
#ifndef MEMORYMANAGER_H
|
||||
#define MEMORYMANAGER_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "SqList.h"
|
||||
|
||||
|
||||
#define MAXSIZE 100 // 最大内存量
|
||||
#define e 0 // 容差
|
||||
|
||||
#define BYTE sizeof(char) // 1个字节
|
||||
|
||||
|
||||
// 内存记录类型定义
|
||||
typedef struct {
|
||||
int addr; // 新地址域,存储内存块的当前最新地址,初始值是空间首地址
|
||||
int size; // 块大小
|
||||
int tag; // 标志域,指示内存是正在使用(1)还是空闲状态(0)
|
||||
|
||||
/* 存储块之间的链接关系,这与用户在虚拟地址层看到的链接关系可能并不一致 */
|
||||
int pre; // 前驱
|
||||
int next; // 后继
|
||||
|
||||
int oldAddr; // 进行存储紧缩后的旧地址
|
||||
} Record;
|
||||
|
||||
// 可用空间类型定义
|
||||
typedef struct {
|
||||
void* base; // 内存起始地址
|
||||
SqList recordList; // 内存使用记录
|
||||
int cur; // 记录空闲块的内存记录的位置,初值为1
|
||||
|
||||
/*
|
||||
* 记录虚拟地址。
|
||||
* 这其实是在模拟操作系统的行为:
|
||||
* 用户使用的地址跟硬件的实际地址可能并不一致,所以需要操作系统构造一个虚拟地址集。
|
||||
*/
|
||||
SqList ptrList;
|
||||
} Space;
|
||||
|
||||
|
||||
// 初始化一片可用的存储
|
||||
void InitSpace(Space* space);
|
||||
|
||||
// 分配大小为n的内存,并返回指向该内存的虚拟地址
|
||||
int* AllocMemory(Space* space, int n);
|
||||
|
||||
// 释放虚拟地址p处的内存
|
||||
void FreeMemory(Space* space, int* p);
|
||||
|
||||
// 将虚拟地址addr转换为底层的真实地址
|
||||
void* getPtr(Space space, const int* addr);
|
||||
|
||||
// 打印内存布局,显示格式为:首地址 块大小 标志域 | 前驱 后继 | 数据
|
||||
void PrintMemoryLayout(Space space);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
/*=============================
|
||||
* 线性表的顺序存储结构(顺序表)
|
||||
*
|
||||
* 包含算法: 2.3、2.4、2.5、2.6
|
||||
=============================*/
|
||||
|
||||
#include "SqList.h"
|
||||
|
||||
/*
|
||||
* ████████ 算法2.3 ████████
|
||||
*
|
||||
* 初始化
|
||||
*
|
||||
* 初始化成功则返回OK,否则返回ERROR。
|
||||
*/
|
||||
Status InitList(SqList* L) {
|
||||
// 分配指定容量的内存,如果分配失败,则返回NULL
|
||||
(*L).elem = (ElemType*) malloc(LIST_INIT_SIZE * sizeof(ElemType));
|
||||
if((*L).elem == NULL) {
|
||||
// 存储内存失败
|
||||
exit(OVERFLOW);
|
||||
}
|
||||
|
||||
(*L).length = 0; // 初始化顺序表长度为0
|
||||
(*L).listsize = LIST_INIT_SIZE; // 顺序表初始内存分配量
|
||||
|
||||
return OK; // 初始化成功
|
||||
}
|
||||
|
||||
/*
|
||||
* 计数
|
||||
*
|
||||
* 返回顺序表包含的有效元素的数量。
|
||||
*/
|
||||
int ListLength(SqList L) {
|
||||
return L.length;
|
||||
}
|
||||
|
||||
/*
|
||||
* 取值
|
||||
*
|
||||
* 获取顺序表中第i个元素,将其存储到e中。
|
||||
* 如果可以找到,返回OK,否则,返回ERROR。
|
||||
*
|
||||
*【备注】
|
||||
* 教材中i的含义是元素位置,从1开始计数,但这不符合编码的通用约定。
|
||||
* 通常,i的含义应该指索引,即从0开始计数。
|
||||
*/
|
||||
Status GetElem(SqList L, int i, ElemType* e) {
|
||||
// 因为i的含义是位置,所以其合法范围是:[1, length]
|
||||
if(i < 1 || i > L.length) {
|
||||
return ERROR; //i值不合法
|
||||
}
|
||||
|
||||
*e = L.elem[i - 1];
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* ████████ 算法2.4 ████████
|
||||
*
|
||||
* 插入
|
||||
*
|
||||
* 向顺序表第i个位置上插入e,插入成功则返回OK,否则返回ERROR。
|
||||
*
|
||||
*【备注】
|
||||
* 教材中i的含义是元素位置,从1开始计数
|
||||
*/
|
||||
Status ListInsert(SqList* L, int i, ElemType e) {
|
||||
ElemType* newbase;
|
||||
ElemType* p, * q;
|
||||
|
||||
// 确保顺序表结构存在
|
||||
if(L == NULL || (*L).elem == NULL) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// i值越界
|
||||
if(i < 1 || i > (*L).length + 1) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// 若存储空间已满,则增加新空间
|
||||
if((*L).length >= (*L).listsize) {
|
||||
// 基于现有空间扩容
|
||||
newbase = (ElemType*) realloc((*L).elem, ((*L).listsize + LISTINCREMENT) * sizeof(ElemType));
|
||||
if(newbase == NULL) {
|
||||
// 存储内存失败
|
||||
exit(OVERFLOW);
|
||||
}
|
||||
|
||||
// 新基址
|
||||
(*L).elem = newbase;
|
||||
// 存的存储空间
|
||||
(*L).listsize += LISTINCREMENT;
|
||||
}
|
||||
|
||||
// q为插入位置
|
||||
q = &(*L).elem[i - 1];
|
||||
|
||||
// 1.右移元素,腾出位置
|
||||
for(p = &(*L).elem[(*L).length - 1]; p >= q; --p) {
|
||||
*(p + 1) = *p;
|
||||
}
|
||||
|
||||
// 2.插入e
|
||||
*q = e;
|
||||
|
||||
// 3.表长增1
|
||||
(*L).length++;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* ████████ 算法2.5 ████████
|
||||
*
|
||||
* 删除
|
||||
*
|
||||
* 删除顺序表第i个位置上的元素,并将被删除元素存储到e中。
|
||||
* 删除成功则返回OK,否则返回ERROR。
|
||||
*
|
||||
*【备注】
|
||||
* 教材中i的含义是元素位置,从1开始计数
|
||||
*/
|
||||
Status ListDelete(SqList* L, int i, ElemType* e) {
|
||||
ElemType* p, * q;
|
||||
|
||||
// 确保顺序表结构存在
|
||||
if(L == NULL || (*L).elem == NULL) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// i值越界
|
||||
if(i < 1 || i > (*L).length) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// p为被删除元素的位置
|
||||
p = &(*L).elem[i - 1];
|
||||
|
||||
// 1.获取被删除元素
|
||||
*e = *p;
|
||||
|
||||
// 表尾元素位置
|
||||
q = (*L).elem + (*L).length - 1;
|
||||
|
||||
// 2.左移元素,被删除元素的位置上会有新元素进来
|
||||
for(++p; p <= q; ++p) {
|
||||
*(p - 1) = *p;
|
||||
}
|
||||
|
||||
// 3.表长减1
|
||||
(*L).length--;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* 遍历
|
||||
*
|
||||
* 用visit函数访问顺序表L
|
||||
*/
|
||||
void ListTraverse(SqList L, void(Visit)(ElemType)) {
|
||||
int i;
|
||||
|
||||
for(i = 0; i < L.length; i++) {
|
||||
Visit(L.elem[i]);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/*=============================
|
||||
* 线性表的顺序存储结构(顺序表)
|
||||
*
|
||||
* 包含算法: 2.3、2.4、2.5、2.6
|
||||
=============================*/
|
||||
|
||||
#ifndef SQLIST_H
|
||||
#define SQLIST_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> // 提供malloc、realloc、free、exit原型
|
||||
#include "Status.h" //**▲01 绪论**//
|
||||
|
||||
/* 宏定义 */
|
||||
#define LIST_INIT_SIZE 100 // 顺序表存储空间的初始分配量
|
||||
#define LISTINCREMENT 10 // 顺序表存储空间的分配增量
|
||||
|
||||
|
||||
/* 顺序表元素类型定义 */
|
||||
typedef void* ElemType;
|
||||
|
||||
/*
|
||||
* 顺序表结构
|
||||
*
|
||||
* 注:elem在使用前需要先为其分配内存,且元素从elem[0]处开始存储
|
||||
*/
|
||||
typedef struct {
|
||||
ElemType* elem; // 顺序表存储空间的基址(指向顺序表所占内存的起始位置)
|
||||
int length; // 当前顺序表长度(包含多少元素)
|
||||
int listsize; // 当前分配的存储容量(可以存储多少元素)
|
||||
} SqList;
|
||||
|
||||
|
||||
/*
|
||||
* ████████ 算法2.3 ████████
|
||||
*
|
||||
* 初始化
|
||||
*
|
||||
* 初始化成功则返回OK,否则返回ERROR。
|
||||
*/
|
||||
Status InitList(SqList* L);
|
||||
|
||||
/*
|
||||
* 计数
|
||||
*
|
||||
* 返回顺序表包含的有效元素的数量。
|
||||
*/
|
||||
int ListLength(SqList L);
|
||||
|
||||
/*
|
||||
* 取值
|
||||
*
|
||||
* 获取顺序表中第i个元素,将其存储到e中。
|
||||
* 如果可以找到,返回OK,否则,返回ERROR。
|
||||
*
|
||||
*【备注】
|
||||
* 教材中i的含义是元素位置,从1开始计数,但这不符合编码的通用约定。
|
||||
* 通常,i的含义应该指索引,即从0开始计数。
|
||||
*/
|
||||
Status GetElem(SqList L, int i, ElemType* e);
|
||||
|
||||
/*
|
||||
* ████████ 算法2.4 ████████
|
||||
*
|
||||
* 插入
|
||||
*
|
||||
* 向顺序表第i个位置上插入e,插入成功则返回OK,否则返回ERROR。
|
||||
*
|
||||
*【备注】
|
||||
* 教材中i的含义是元素位置,从1开始计数
|
||||
*/
|
||||
Status ListInsert(SqList* L, int i, ElemType e);
|
||||
|
||||
/*
|
||||
* ████████ 算法2.5 ████████
|
||||
*
|
||||
* 删除
|
||||
*
|
||||
* 删除顺序表第i个位置上的元素,并将被删除元素存储到e中。
|
||||
* 删除成功则返回OK,否则返回ERROR。
|
||||
*
|
||||
*【备注】
|
||||
* 教材中i的含义是元素位置,从1开始计数
|
||||
*/
|
||||
Status ListDelete(SqList* L, int i, ElemType* e);
|
||||
|
||||
/*
|
||||
* 遍历
|
||||
*
|
||||
* 用visit函数访问顺序表L
|
||||
*/
|
||||
void ListTraverse(SqList L, void (Visit)(ElemType));
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
| 首地址 | 块大小 | 标志域 | 前驱指针 | 后继指针 |
|
||||
| :----: | :----: | :----: | :----: | :----: |
|
||||
| 0 | 5 | 1 | -1 | 10 |
|
||||
| 5 | 5 | 0 | -1 | -1 |
|
||||
| 10 | 5 | 1 | 15 | 40 |
|
||||
| 15 | 10 | 1 | -1 | -1 |
|
||||
| 25 | 5 | 0 | -1 | -1 |
|
||||
| 30 | 10 | 0 | -1 | -1 |
|
||||
| 40 | 5 | 1 | 45 | 65 |
|
||||
| 45 | 10 | 1 | -1 | -1 |
|
||||
| 55 | 5 | 0 | -1 | -1 |
|
||||
| 60 | 5 | 0 | -1 | -1 |
|
||||
| 65 | 5 | 1 | 85 | -1 |
|
||||
| 70 | 5 | 0 | -1 | -1 |
|
||||
| 75 | 10 | 0 | -1 | -1 |
|
||||
| 85 | 5 | 1 | 90 | -1 |
|
||||
| 90 | 10 | 1 | -1 | -1 |
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 55 KiB |
@@ -0,0 +1,126 @@
|
||||
#include <stdio.h>
|
||||
#include "Status.h"
|
||||
#include "SqStack.h"
|
||||
|
||||
/* 宏定义 */
|
||||
#define MAXSIZE 200 // 内存总大小
|
||||
|
||||
|
||||
/* 空闲空间类型定义 */
|
||||
typedef struct {
|
||||
void* base; // 可用空间内存的起始地址
|
||||
int size; // 空闲空间大小(按字节计数)
|
||||
SqStack block; // 已经使用的内存块大小,先申请的内存信息先入栈
|
||||
} Space;
|
||||
|
||||
|
||||
// 初始化内存空间及内存信息栈
|
||||
void InitSpace(Space* space);
|
||||
|
||||
// 打印内存布局,查看当前内存的使用情况
|
||||
void PrintMemoryLayout(Space space);
|
||||
|
||||
// 申请大小为n的内存块,返回申请到的内存起始地址
|
||||
void* Algo_8_11(Space* space, int n);
|
||||
|
||||
// 回收内存,遵循"最后分配者最先释放"的原则
|
||||
Status Algo_8_12(Space* space);
|
||||
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
Space space;
|
||||
int s[5] = {50, 50, 150, 100, 50}; // 定义内存申请数量
|
||||
int i;
|
||||
|
||||
// 初始化内存
|
||||
InitSpace(&space);
|
||||
PrintMemoryLayout(space);
|
||||
printf("\n");
|
||||
|
||||
// 申请/释放内存
|
||||
for(i = 0; i < 5; i++) {
|
||||
printf("申请 %d 个内存后...\n", s[i]);
|
||||
Algo_8_11(&space, s[i]);
|
||||
PrintMemoryLayout(space);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// 初始化一块空闲空间
|
||||
void InitSpace(Space* space) {
|
||||
// 申请MAX字节的空间(假设总能初始化成功)
|
||||
space->base = malloc(MAXSIZE);
|
||||
space->size = MAXSIZE;
|
||||
|
||||
// 初始化内存信息栈
|
||||
InitStack(&(space->block));
|
||||
}
|
||||
|
||||
// 打印内存布局,查看当前内存的使用情况
|
||||
void PrintMemoryLayout(Space space) {
|
||||
int i;
|
||||
|
||||
for(i = 1; i <= MAXSIZE; i++) {
|
||||
if(i <= space.size) {
|
||||
printf("□");
|
||||
} else {
|
||||
printf("■");
|
||||
}
|
||||
|
||||
// 预定每隔20个换一下行
|
||||
if(i % 20 == 0) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
if(MAXSIZE % 20 != 0) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
// 申请大小为n的内存块,返回申请到的内存起始地址
|
||||
void* Algo_8_11(Space* space, int n) {
|
||||
|
||||
/*
|
||||
* 如果可用的内存数量少于申请的内存数量,
|
||||
* 则需要释放最近申请使用的内存以腾出空间。
|
||||
*/
|
||||
while(space->size < n && Algo_8_12(space) == OK) {
|
||||
// 直到空闲内存满足申请要求,或者全部占用内存已经释放,才会退出循环
|
||||
}
|
||||
|
||||
// 如果没有足够的内存可用,则返回空指针
|
||||
if(space->size < n) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 可用空间减小
|
||||
space->size -= n;
|
||||
|
||||
// 记下成功申请到的内存
|
||||
Push(&(space->block), n);
|
||||
|
||||
// 返回申请到的内存起始地址(VS里运行需要指定指针类型,这里设定为一个字节)
|
||||
return (char*)(space->base) + space->size;
|
||||
}
|
||||
|
||||
// 回收内存,遵循"最后分配者最先释放"的原则
|
||||
Status Algo_8_12(Space* space) {
|
||||
int e;
|
||||
|
||||
// 已经没有可释放内存时,返回ERROR
|
||||
if(StackEmpty(space->block)) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// 将最后申请的内存释放掉
|
||||
Pop(&(space->block), &e);
|
||||
|
||||
// 可用空间增大
|
||||
space->size += e;
|
||||
|
||||
return OK;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{92D19D62-5A91-436F-BCAC-672018B7B67B}</ProjectGuid>
|
||||
<RootNamespace>My08110812</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<IncludePath>$(SolutionDir)\..\Status;$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>$(SolutionDir)\..\Status\Status.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<SubSystem>Console</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="08.11-08.12.c" />
|
||||
<ClCompile Include="SqStack.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="SqStack.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="源文件">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="头文件">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="资源文件">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="08.11-08.12.c">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SqStack.c">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="SqStack.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
</Project>
|
||||
@@ -0,0 +1,90 @@
|
||||
/*=========================
|
||||
* 栈的顺序存储结构(顺序栈)
|
||||
==========================*/
|
||||
|
||||
#include "SqStack.h" //**▲03 栈和队列**//
|
||||
|
||||
/*
|
||||
* 初始化
|
||||
*
|
||||
* 构造一个空栈。初始化成功则返回OK,否则返回ERROR。
|
||||
*/
|
||||
Status InitStack(SqStack* S) {
|
||||
if(S == NULL) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
(*S).base = (SElemType*) malloc(STACK_INIT_SIZE * sizeof(SElemType));
|
||||
if((*S).base == NULL) {
|
||||
exit(OVERFLOW);
|
||||
}
|
||||
|
||||
(*S).top = (*S).base;
|
||||
(*S).stacksize = STACK_INIT_SIZE;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* 判空
|
||||
*
|
||||
* 判断顺序栈中是否包含有效数据。
|
||||
*
|
||||
* 返回值:
|
||||
* TRUE : 顺序栈为空
|
||||
* FALSE: 顺序栈不为空
|
||||
*/
|
||||
Status StackEmpty(SqStack S) {
|
||||
if(S.top == S.base) {
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 入栈
|
||||
*
|
||||
* 将元素e压入到栈顶。
|
||||
*/
|
||||
Status Push(SqStack* S, SElemType e) {
|
||||
if(S == NULL || (*S).base == NULL) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// 栈满时,追加存储空间
|
||||
if((*S).top - (*S).base >= (*S).stacksize) {
|
||||
(*S).base = (SElemType*) realloc((*S).base, ((*S).stacksize + STACKINCREMENT) * sizeof(SElemType));
|
||||
if((*S).base == NULL) {
|
||||
exit(OVERFLOW); // 存储分配失败
|
||||
}
|
||||
|
||||
(*S).top = (*S).base + (*S).stacksize;
|
||||
(*S).stacksize += STACKINCREMENT;
|
||||
}
|
||||
|
||||
// 进栈先赋值,栈顶指针再自增
|
||||
*(S->top++) = e;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* 出栈
|
||||
*
|
||||
* 将栈顶元素弹出,并用e接收。
|
||||
*/
|
||||
Status Pop(SqStack* S, SElemType* e) {
|
||||
if(S == NULL || (*S).base == NULL) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
if((*S).top == (*S).base) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// 出栈栈顶指针先递减,再赋值
|
||||
*e = *(--(*S).top);
|
||||
|
||||
return OK;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*=========================
|
||||
* 栈的顺序存储结构(顺序栈)
|
||||
==========================*/
|
||||
|
||||
#ifndef SQSTACK_H
|
||||
#define SQSTACK_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> // 提供malloc、realloc、free、exit原型
|
||||
#include "Status.h" //**▲01 绪论**//
|
||||
|
||||
/* 宏定义 */
|
||||
#define STACK_INIT_SIZE 100 // 顺序栈存储空间的初始分配量
|
||||
#define STACKINCREMENT 10 // 顺序栈存储空间的分配增量
|
||||
|
||||
/* 顺序栈元素类型定义 */
|
||||
typedef int SElemType;
|
||||
|
||||
// 顺序栈元素结构
|
||||
typedef struct {
|
||||
SElemType* base; // 栈底指针
|
||||
SElemType* top; // 栈顶指针
|
||||
int stacksize; // 当前已分配的存储空间,以元素为单位
|
||||
} SqStack;
|
||||
|
||||
|
||||
/*
|
||||
* 初始化
|
||||
*
|
||||
* 构造一个空栈。初始化成功则返回OK,否则返回ERROR。
|
||||
*/
|
||||
Status InitStack(SqStack* S);
|
||||
|
||||
/*
|
||||
* 判空
|
||||
*
|
||||
* 判断顺序栈中是否包含有效数据。
|
||||
*
|
||||
* 返回值:
|
||||
* TRUE : 顺序栈为空
|
||||
* FALSE: 顺序栈不为空
|
||||
*/
|
||||
Status StackEmpty(SqStack S);
|
||||
|
||||
/*
|
||||
* 入栈
|
||||
*
|
||||
* 将元素e压入到栈顶。
|
||||
*/
|
||||
Status Push(SqStack* S, SElemType e);
|
||||
|
||||
/*
|
||||
* 出栈
|
||||
*
|
||||
* 将栈顶元素弹出,并用e接收。
|
||||
*/
|
||||
Status Pop(SqStack* S, SElemType* e);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,65 @@
|
||||
#include <stdio.h>
|
||||
#include "BoundaryTagMethod.h" //**▲08 动态存储管理**//
|
||||
|
||||
/*
|
||||
* 边界标识法的内存回收算法
|
||||
*
|
||||
* 对指针p处的内存进行释放
|
||||
*/
|
||||
void Algo_8_13(Space* pav, Space p);
|
||||
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
Space pav;
|
||||
Space p[12]; // 记录申请到的内存的指针
|
||||
int s[12] = {10, 20, 30, 50, 5, 15, 10, 5, 15, 15, 2, 20}; // 申请的空间大小
|
||||
int i = 0;
|
||||
|
||||
printf("████████ InitSpace \n");
|
||||
{
|
||||
int max = 200; // 初值建议为20的倍数,目的是打印出来可以对齐
|
||||
|
||||
printf("初始化包含 %d 个\"字\"的内存块后,当前内存布局为:\n", max);
|
||||
pav = InitSpace(max);
|
||||
PrintMemoryLayout();
|
||||
printf("\n");
|
||||
}
|
||||
PressEnterToContinue(debug);
|
||||
|
||||
printf("████████ AllocBoundTag \n");
|
||||
{
|
||||
for(i = 0; i < 12; i++) {
|
||||
printf("████ %2d> 申请 %d 个\"字\"的内存后,当前内存布局为:\n", i + 1, s[i]);
|
||||
p[i] = AllocBoundTag(&pav, s[i]);
|
||||
PrintMemoryLayout();
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
PressEnterToContinue(debug);
|
||||
|
||||
printf("████████ FreeBoundTag \n");
|
||||
{
|
||||
// 定义一个指针回收顺序
|
||||
int a[10] = {7, 3, 10, 6, 8, 5, 11, 1, 0, 4};
|
||||
|
||||
for(i = 0; i < 10; i++) {
|
||||
printf("回收 p%d 指向的内存...\n", a[i] + 1);
|
||||
Algo_8_13(&pav, p[a[i]]);
|
||||
PrintMemoryLayout();
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
PressEnterToContinue(debug);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 边界标识法的内存回收算法
|
||||
*
|
||||
* 对指针p处的内存进行释放
|
||||
*/
|
||||
void Algo_8_13(Space* pav, Space p) {
|
||||
FreeBoundTag(pav, p);
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{B8418DCB-E6A4-4C39-97FC-E57B694A4512}</ProjectGuid>
|
||||
<RootNamespace>My0813</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<IncludePath>$(SolutionDir)\..\Status;$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>$(SolutionDir)\..\Status\Status.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<SubSystem>Console</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="08.13.c" />
|
||||
<ClCompile Include="BoundaryTagMethod.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="BoundaryTagMethod.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="源文件">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="头文件">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="资源文件">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="08.13.c">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="BoundaryTagMethod.c">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="BoundaryTagMethod.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
</Project>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,96 @@
|
||||
/*==============
|
||||
* 边界标识法
|
||||
*
|
||||
* 包含算法: 8.1
|
||||
===============*/
|
||||
|
||||
#ifndef BOUNDARYTAGMETHOD_H
|
||||
#define BOUNDARYTAGMETHOD_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "Status.h" //**▲01 绪论**//
|
||||
|
||||
/* 宏定义 */
|
||||
#define e 5 // 分配空间时用到的容差
|
||||
#define FootLoc(p) p+(p->size)-1 // 将p指针定位到p所指内存块的底部
|
||||
|
||||
|
||||
/*
|
||||
* 内存"字"的类型定义
|
||||
*
|
||||
* 所谓"字"是指空间分配的最小单位,它不是字节。
|
||||
* 一个"字"有多大,取决于对"字"结构是如何定义的。
|
||||
*/
|
||||
typedef struct WORD {
|
||||
|
||||
/*
|
||||
* 注:
|
||||
* 教材中将llink和uplink封装在了一个联合体中,个人感觉这个封装有些鸡肋。
|
||||
* 一方面,head和foot的公共部分其实只有tag,如果真想用联合体,那么应当把size和rlink也封装起来。
|
||||
* 另一方面,这个封装节省的空间很有限,而且直接影响了代码的可读性。
|
||||
* 这里只是教学代码,而不是真实的系统代码,所以空间考虑在其次,原理展示为首要任务。
|
||||
* 此外,教材中的伪码中也并没有考虑这个联合体,而是直接进行操作的。
|
||||
* 综上所述,这里去除了教材中的联合体结构。
|
||||
* 如想观察带有联合体的写法,可以参考CFree分支的代码。
|
||||
*/
|
||||
|
||||
int tag; // 块标志,0空闲,1占用,头部和尾部均有
|
||||
|
||||
struct WORD* llink; // 头部域,指向前驱结点
|
||||
struct WORD* rlink; // 头部域,指向后继结点
|
||||
int size; // 头部域,块大小
|
||||
|
||||
struct WORD* uplink; // 底部域,指向本结点头部
|
||||
} WORD;
|
||||
|
||||
typedef WORD* Space; // Space:指向可利用空间的指针类型
|
||||
|
||||
|
||||
/*
|
||||
* 初始化一块大小为n个字的内存,并返回指向该内存的起点的指针
|
||||
* 注:返回的初始内存已经包含了head和foot。
|
||||
*/
|
||||
Space InitSpace(int n);
|
||||
|
||||
/*
|
||||
* ████████ 算法8.1 ████████
|
||||
*
|
||||
* 边界标识法的内存分配算法
|
||||
*
|
||||
* 从空间pav中申请一块大小至少为n的空间,并返回指向申请到的空间的指针。如果分配失败,则返回NULL。
|
||||
* 为了使分配后的剩余块尽量均匀分布,每次分配完之后都要把空间指针pav向前移动,具体描述参见教材。
|
||||
*
|
||||
* 注:
|
||||
* 1.这里采用首次拟合法,即一遇到满足条件的内存块就进行分配操作。
|
||||
* 2.为了避免空间碎片化过快,这里增加了一个容差e,具体含义参考教材描述。
|
||||
* 3.这里申请分配n个字的空间,指的是已经完成换算的空间。
|
||||
* 比如用户想要容量为10个字的空间,但每个空间又包含head和foot这两个字存储空间使用信息,
|
||||
* 因此实际上分配的空间大小应为12个字,这个"12"就是n的含义。
|
||||
* 教材中提到"head和foot在分配时忽略不计",这样是为了伪码书写的方便。实际写代码时,这两个空间是不能忽略的。
|
||||
* 但是如果按照上面的描述,把n解释为已经换算后空间,而不是用户原始申请的空间,
|
||||
* 那么既满足了没有忽略空间,又满足了在书面效果上,跟教材伪码统一,可谓两全其美。
|
||||
*/
|
||||
Space AllocBoundTag(Space* pav, int n);
|
||||
|
||||
/*
|
||||
* 边界标识法的内存回收算法
|
||||
*
|
||||
* 对指针p处的内存进行释放
|
||||
*/
|
||||
void FreeBoundTag(Space* pav, Space p);
|
||||
|
||||
/*
|
||||
* 打印内存布局,查看当前内存的使用情况
|
||||
* 注:仅限内部测试使用
|
||||
*/
|
||||
void PrintMemoryLayout();
|
||||
|
||||
/*
|
||||
* 计算可用的空闲空间容量
|
||||
*
|
||||
* 注:仅限内部使用,用在日志打印中
|
||||
*/
|
||||
static int AvailableSpace(Space pav);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,66 @@
|
||||
#include <stdio.h>
|
||||
#include "BuddySystem.h" //**▲08 动态存储管理**//
|
||||
|
||||
/*
|
||||
* 伙伴系统的内存回收算法
|
||||
*
|
||||
* 对指针p处的内存进行释放(这类似于free(),只是对内存进行释放操作,至于置空指针p的操作,应交给调用方完成)
|
||||
*
|
||||
* 注:这里没有验证p的取值,调用方应当确保p在合规的范围
|
||||
*/
|
||||
void Algo_8_14(FreeList avail, WORD* p);
|
||||
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
FreeList avail;
|
||||
WORD* p[8]; // 记录申请到的内存的指针
|
||||
int s[8] = {4, 5, 6, 7, 1, 5, 3, 9}; // 申请的空间大小
|
||||
int i;
|
||||
|
||||
printf("████████ InitSpace \n");
|
||||
{
|
||||
printf("初始化一个内存块...\n");
|
||||
InitSpace(avail);
|
||||
PrintMemoryLayout();
|
||||
printf("\n");
|
||||
}
|
||||
PressEnterToContinue(debug);
|
||||
|
||||
printf("████████ AllocBuddy \n");
|
||||
{
|
||||
for(i = 0; i < 8; i++) {
|
||||
printf("申请大小为 %d 个字的内存块...\n", s[i]);
|
||||
p[i] = AllocBuddy(avail, s[i]);
|
||||
PrintMemoryLayout();
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
PressEnterToContinue(debug);
|
||||
|
||||
printf("████████ FreeBuddy \n");
|
||||
{
|
||||
// 定义一个指针回收顺序
|
||||
int a[8] = {2, 0, 5, 7, 1, 4, 3, 6};
|
||||
|
||||
for(i = 0; i < 8; i++) {
|
||||
Algo_8_14(avail, p[a[i]]);
|
||||
PrintMemoryLayout();
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
PressEnterToContinue(debug);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 伙伴系统的内存回收算法
|
||||
*
|
||||
* 对指针p处的内存进行释放(这类似于free(),只是对内存进行释放操作,至于置空指针p的操作,应交给调用方完成)
|
||||
*
|
||||
* 注:这里没有验证p的取值,调用方应当确保p在合规的范围
|
||||
*/
|
||||
void Algo_8_14(FreeList avail, WORD* p) {
|
||||
FreeBuddy(avail, p);
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{5CA72478-69D3-4ECB-A4FC-C4F3B9B9E370}</ProjectGuid>
|
||||
<RootNamespace>My0814</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<IncludePath>$(SolutionDir)\..\Status;$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>$(SolutionDir)\..\Status\Status.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<SubSystem>Console</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="08.14.c" />
|
||||
<ClCompile Include="BuddySystem.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="BuddySystem.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="源文件">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="头文件">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="资源文件">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="08.14.c">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="BuddySystem.c">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="BuddySystem.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
</Project>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,89 @@
|
||||
/*==============
|
||||
* 伙伴系统
|
||||
*
|
||||
* 包含算法: 8.2
|
||||
===============*/
|
||||
|
||||
#ifndef BUDDYSYSTEM_H
|
||||
#define BUDDYSYSTEM_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include "Status.h" //**▲01 绪论**//
|
||||
|
||||
/* 宏定义 */
|
||||
#define M 6 // 假设总空间大小为2^M个字,子表个数为M+1
|
||||
|
||||
|
||||
/*
|
||||
* 内存"字"的类型定义
|
||||
*
|
||||
* 所谓"字"是指空间分配的最小单位,它不是字节。
|
||||
* 一个"字"有多大,取决于对"字"结构是如何定义的。
|
||||
*/
|
||||
typedef struct WORD {
|
||||
struct WORD* llink; // 头部域的前驱指针
|
||||
struct WORD* rlink; // 头部域的后继指针
|
||||
int tag; // 头部域的块标志,0:空闲,1:占用
|
||||
int kval; // 指示块的大小,比如其值为K时,表示该块的大小为2^K
|
||||
} WORD;
|
||||
|
||||
// 表头向量类型
|
||||
typedef struct HeadNode {
|
||||
int nodesize; // 该链表的空闲块的大小
|
||||
WORD* first; // 该链表的表头指针
|
||||
} FreeList[M + 1];
|
||||
|
||||
|
||||
/*
|
||||
* 初始化一块大小为2^M个字的内存,并返回指向该内存的起点的指针
|
||||
* 注:返回的初始内存已经包含了head。
|
||||
*/
|
||||
void InitSpace(FreeList avail);
|
||||
|
||||
/*
|
||||
* ████████ 算法8.2 ████████
|
||||
*
|
||||
* 伙伴系统的内存分配算法
|
||||
*
|
||||
* 从空间avail中申请一块大小至少为n(原始值)的空间,并返回指向申请到的空间的指针。如果分配失败,则返回NULL。
|
||||
*
|
||||
* 注:
|
||||
* 1.这里采用首次拟合法,即一遇到满足条件的内存块就进行分配操作。
|
||||
* 2.这里申请分配n个字的空间,指的是用户申请的原始空间。
|
||||
* 实际在申请时,还要考虑到每个块前面有1个字的head信息,即经过换算后,实际需要申请(n+1)个字。
|
||||
* 这里的n与算法8.1里面的n含义正好相反,需要注意。
|
||||
*/
|
||||
WORD* AllocBuddy(FreeList avail, int n);
|
||||
|
||||
/*
|
||||
* 伙伴系统的内存回收算法
|
||||
*
|
||||
* 对指针p处的内存进行释放(这类似于free(),只是对内存进行释放操作,至于置空指针p的操作,应交给调用方完成)
|
||||
*
|
||||
* 注:这里没有验证p的取值,调用方应当确保p在合规的范围
|
||||
*/
|
||||
void FreeBuddy(FreeList avail, WORD* p);
|
||||
|
||||
/*
|
||||
* 打印内存布局,查看当前内存的使用情况
|
||||
* 注:仅限内部测试使用
|
||||
*/
|
||||
void PrintMemoryLayout();
|
||||
|
||||
/*
|
||||
* 查找块p的伙伴
|
||||
*
|
||||
* 将一个空闲块对半分裂后,会生成的两个小空闲块,这两个小空闲块互为伙伴。
|
||||
*
|
||||
* 计算伙伴的算法为:
|
||||
* 对于起始地址为p,大小为2^k的内存块:
|
||||
* 1.若 p MOD 2^(k+1) == 0 ,则p的伙伴块的起始地址为p+2^k,
|
||||
* 2.若 p MOD 2^(k+1) == 2^k ,则p的伙伴块的起始地址为p-2^k。
|
||||
*
|
||||
* 注:仅限内部使用,用在回收算法中
|
||||
*/
|
||||
static WORD* Buddy(WORD* p);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,85 @@
|
||||
#include <stdio.h>
|
||||
#include "MemoryManager.h"
|
||||
|
||||
/*
|
||||
* 内存整理
|
||||
*
|
||||
* 将空闲块收集起来,链接成一条空闲块链表。
|
||||
*/
|
||||
void Algo_8_15(Space* space);
|
||||
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
Space space;
|
||||
int i;
|
||||
int a[11] = {10, 20, 30, 15, 20, 5, -1, -3, 0, 15, 10};
|
||||
WORD* p[11];
|
||||
|
||||
InitSpace(&space);
|
||||
printf("初始内存布局:\n");
|
||||
PrintMemoryLayout(space);
|
||||
|
||||
/*
|
||||
* 注:
|
||||
* 申请a[4]时,仅剩25个"字",当前容差是5,因此本次会直接分配20+5=25个"字"
|
||||
* 申请a[5]时,已经没有可用的字,所以申请失败
|
||||
* 申请a[10]时,处在容差范围内,会整块分配
|
||||
*/
|
||||
for(i = 0; i < 11; i++) {
|
||||
if(a[i] > 0) {
|
||||
printf("+ 申请 %d 个字的存储\n", a[i]);
|
||||
p[i] = AllocMemory(&space, a[i]);
|
||||
} else {
|
||||
printf("- 释放 %d 个字的存储\n", a[-a[i]]);
|
||||
FreeMemory(&space, p[-a[i]]);
|
||||
}
|
||||
|
||||
PrintMemoryLayout(space);
|
||||
|
||||
if(i == 8) {
|
||||
printf("内存整理...\n");
|
||||
Algo_8_15(&space);
|
||||
PrintMemoryLayout(space);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 内存整理
|
||||
*
|
||||
* 将空闲块收集起来,链接成一条空闲块链表。
|
||||
*/
|
||||
void Algo_8_15(Space* space) {
|
||||
WORD* p, * q;
|
||||
|
||||
space->avail = NULL;
|
||||
|
||||
q = NULL;
|
||||
|
||||
// 遍历整个堆
|
||||
for(p = space->lowbound; p < space->highbound; p += p->cellsize) {
|
||||
if(p->tag == 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 先把后继置空
|
||||
p->next = NULL;
|
||||
|
||||
// 遇到了第一个空闲块
|
||||
if(space->avail == NULL) {
|
||||
space->avail = p;
|
||||
q = p;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 如果两个空闲块地址不相邻,则进行链接
|
||||
if(q + q->cellsize != p) {
|
||||
q->next = p;
|
||||
|
||||
// 对于地址相邻的空闲块,要合并
|
||||
} else {
|
||||
q->cellsize += p->cellsize;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{597EDEF1-E7A2-4CCB-A036-13D81A98F053}</ProjectGuid>
|
||||
<RootNamespace>My0815</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<IncludePath>$(SolutionDir)\..\Status;$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>$(SolutionDir)\..\Status\Status.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<SubSystem>Console</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="08.15.c" />
|
||||
<ClCompile Include="MemoryManager.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="MemoryManager.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="源文件">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="头文件">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="资源文件">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="08.15.c">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MemoryManager.c">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="MemoryManager.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
</Project>
|
||||
@@ -0,0 +1,131 @@
|
||||
/*=======================
|
||||
* 存储管理,适用于习题8.15
|
||||
========================*/
|
||||
|
||||
#include "MemoryManager.h"
|
||||
|
||||
// 初始化一片可用的存储
|
||||
void InitSpace(Space* space) {
|
||||
space->avail = (WORD*) malloc(MAXSIZE * sizeof(WORD));
|
||||
space->avail->tag = 0;
|
||||
space->avail->cellsize = MAXSIZE;
|
||||
space->avail->next = NULL;
|
||||
|
||||
space->lowbound = space->avail;
|
||||
space->highbound = space->avail + MAXSIZE;
|
||||
}
|
||||
|
||||
// 分配大小为n的内存,并返回指向该内存的虚拟地址
|
||||
WORD* AllocMemory(Space* space, int n) {
|
||||
WORD* p, * q;
|
||||
|
||||
if(space->avail == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p = space->avail;
|
||||
q = NULL;
|
||||
|
||||
// 如果第一个空闲块不满足条件
|
||||
if(p->cellsize < n) {
|
||||
// 查找满足条件的空闲内存
|
||||
while(p != NULL && p->cellsize < n) {
|
||||
q = p;
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
|
||||
// 没有符合条件的空闲内存
|
||||
if(p == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 在容差范围内,则整块分配
|
||||
if(p->cellsize - e <= n) {
|
||||
if(q == NULL) {
|
||||
space->avail = p->next;
|
||||
} else {
|
||||
q->next = p->next;
|
||||
}
|
||||
|
||||
// 分割空闲块
|
||||
} else {
|
||||
|
||||
if(q == NULL) {
|
||||
space->avail += n;
|
||||
space->avail->tag = 0;
|
||||
space->avail->cellsize = p->cellsize - n;
|
||||
space->avail->next = p->next;
|
||||
} else {
|
||||
q->next = p + n;
|
||||
q->next->tag = 0;
|
||||
q->next->cellsize = p->cellsize - n;
|
||||
}
|
||||
|
||||
p->cellsize = n;
|
||||
}
|
||||
|
||||
// 标记为占用
|
||||
p->tag = 1;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
// 释放指针p处的内存
|
||||
void FreeMemory(Space* space, WORD* p) {
|
||||
p->tag = 0; // 简单地标记为空闲,以待后续整理
|
||||
}
|
||||
|
||||
// 打印内存布局
|
||||
void PrintMemoryLayout(Space space) {
|
||||
int i, count;
|
||||
WORD* p;
|
||||
|
||||
// 遍历所有块
|
||||
for(p = space.lowbound; p < space.highbound; p += p->cellsize) {
|
||||
if(p->tag == 0) {
|
||||
p->flag = -1; // 暂时标记为"不可用"的空闲块
|
||||
} else {
|
||||
p->flag = 1; // 标记为占用
|
||||
}
|
||||
}
|
||||
|
||||
// 遍历空闲块链表
|
||||
for(p = space.avail; p != NULL; p = p->next) {
|
||||
p->flag = 0; // 更新为"可用"的空闲块
|
||||
}
|
||||
|
||||
count = 0;
|
||||
|
||||
for(p = space.lowbound; p < space.highbound; p += p->cellsize) {
|
||||
for(i = 0; i < p->cellsize; i++) {
|
||||
switch(p->flag) {
|
||||
case -1:
|
||||
printf("△");
|
||||
break;
|
||||
case 0:
|
||||
printf("□");
|
||||
break;
|
||||
case 1:
|
||||
printf("■");
|
||||
break;
|
||||
default:
|
||||
printf("错误的标记!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
count++;
|
||||
// 每隔20个字换一下行
|
||||
if(count % 20 == 0) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(count % 20 != 0) {
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*=======================
|
||||
* 存储管理,适用于习题8.15
|
||||
========================*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef MEMORYMANAGER_H
|
||||
#define MEMORYMANAGER_H
|
||||
|
||||
|
||||
/* 宏定义 */
|
||||
#define MAXSIZE 100 // 内存总容量
|
||||
#define e 5 // 分配空间时用到的容差
|
||||
|
||||
|
||||
/*
|
||||
* 内存"字"的类型定义
|
||||
*
|
||||
* 所谓"字"是指空间分配的最小单位,它不是字节。
|
||||
* 一个"字"有多大,取决于对"字"结构是如何定义的。
|
||||
*/
|
||||
typedef struct WORD {
|
||||
int tag; // 块标志,0空闲,1占用
|
||||
int cellsize; // 当前块的大小
|
||||
struct WORD* next; // 指向下一个空闲块
|
||||
|
||||
|
||||
/*
|
||||
* 使用标记,0代表空闲,1代表占用,-1代表虽然空闲,但是不在空闲链表中。
|
||||
* 这个标记仅用来测试打印功能,并没有其它实质性的用处。
|
||||
*/
|
||||
int flag;
|
||||
} WORD;
|
||||
|
||||
// "堆"空间
|
||||
typedef struct {
|
||||
struct WORD* lowbound; // 空间下界
|
||||
struct WORD* highbound; // 空间上界
|
||||
struct WORD* avail; // 指向可用空间链表
|
||||
} Space;
|
||||
|
||||
|
||||
// 初始化一片可用的存储
|
||||
void InitSpace(Space* space);
|
||||
|
||||
// 分配大小为n的内存,并返回指向该内存的虚拟地址
|
||||
WORD* AllocMemory(Space* space, int n);
|
||||
|
||||
// 释放指针p处的内存
|
||||
void FreeMemory(Space* space, WORD* p);
|
||||
|
||||
// 打印内存布局
|
||||
void PrintMemoryLayout(Space space);
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,81 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{BFA3C1E2-BC09-4DF8-AB69-680C5EE9A7B1}</ProjectGuid>
|
||||
<RootNamespace>My0816</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<IncludePath>$(SolutionDir)\..\Status;$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>$(SolutionDir)\..\Status\Status.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<SubSystem>Console</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="08.16.c" />
|
||||
<ClCompile Include="MemoryManager.c" />
|
||||
<ClCompile Include="SqList.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="MemoryManager.h" />
|
||||
<ClInclude Include="SqList.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="TestData_8_10.md" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="源文件">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="头文件">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="资源文件">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="08.16.c">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MemoryManager.c">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SqList.c">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="MemoryManager.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SqList.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="TestData_8_10.md">
|
||||
<Filter>资源文件</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
</Project>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,63 @@
|
||||
/*=======================
|
||||
* 存储管理,适用于习题8.16
|
||||
========================*/
|
||||
|
||||
#ifndef MEMORYMANAGER_H
|
||||
#define MEMORYMANAGER_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "SqList.h"
|
||||
|
||||
|
||||
#define MAXSIZE 100 // 最大内存量
|
||||
#define e 0 // 容差
|
||||
|
||||
#define BYTE sizeof(char) // 1个字节
|
||||
|
||||
|
||||
// 内存记录类型定义
|
||||
typedef struct {
|
||||
int addr; // 新地址域,存储内存块的当前最新地址,初始值是空间首地址
|
||||
int size; // 块大小
|
||||
int tag; // 标志域,指示内存是正在使用(1)还是空闲状态(0)
|
||||
|
||||
/* 存储块之间的链接关系,这与用户在虚拟地址层看到的链接关系可能并不一致 */
|
||||
int pre; // 前驱
|
||||
int next; // 后继
|
||||
|
||||
int oldAddr; // 进行存储紧缩后的旧地址
|
||||
} Record;
|
||||
|
||||
// 可用空间类型定义
|
||||
typedef struct {
|
||||
void* base; // 内存起始地址
|
||||
SqList recordList; // 内存使用记录
|
||||
int cur; // 记录空闲块的内存记录的位置,初值为1
|
||||
|
||||
/*
|
||||
* 记录虚拟地址。
|
||||
* 这其实是在模拟操作系统的行为:
|
||||
* 用户使用的地址跟硬件的实际地址可能并不一致,所以需要操作系统构造一个虚拟地址集。
|
||||
*/
|
||||
SqList ptrList;
|
||||
} Space;
|
||||
|
||||
|
||||
// 初始化一片可用的存储
|
||||
void InitSpace(Space* space);
|
||||
|
||||
// 分配大小为n的内存,并返回指向该内存的虚拟地址
|
||||
int* AllocMemory(Space* space, int n);
|
||||
|
||||
// 释放虚拟地址p处的内存
|
||||
void FreeMemory(Space* space, int* p);
|
||||
|
||||
// 将虚拟地址addr转换为底层的真实地址
|
||||
void* getPtr(Space space, const int* addr);
|
||||
|
||||
// 打印内存布局,显示格式为:首地址 块大小 标志域 | 前驱 后继 | 数据
|
||||
void PrintMemoryLayout(Space space);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,173 @@
|
||||
/*=============================
|
||||
* 线性表的顺序存储结构(顺序表)
|
||||
*
|
||||
* 包含算法: 2.3、2.4、2.5、2.6
|
||||
=============================*/
|
||||
|
||||
#include "SqList.h"
|
||||
|
||||
/*
|
||||
* ████████ 算法2.3 ████████
|
||||
*
|
||||
* 初始化
|
||||
*
|
||||
* 初始化成功则返回OK,否则返回ERROR。
|
||||
*/
|
||||
Status InitList(SqList* L) {
|
||||
// 分配指定容量的内存,如果分配失败,则返回NULL
|
||||
(*L).elem = (ElemType*) malloc(LIST_INIT_SIZE * sizeof(ElemType));
|
||||
if((*L).elem == NULL) {
|
||||
// 存储内存失败
|
||||
exit(OVERFLOW);
|
||||
}
|
||||
|
||||
(*L).length = 0; // 初始化顺序表长度为0
|
||||
(*L).listsize = LIST_INIT_SIZE; // 顺序表初始内存分配量
|
||||
|
||||
return OK; // 初始化成功
|
||||
}
|
||||
|
||||
/*
|
||||
* 计数
|
||||
*
|
||||
* 返回顺序表包含的有效元素的数量。
|
||||
*/
|
||||
int ListLength(SqList L) {
|
||||
return L.length;
|
||||
}
|
||||
|
||||
/*
|
||||
* 取值
|
||||
*
|
||||
* 获取顺序表中第i个元素,将其存储到e中。
|
||||
* 如果可以找到,返回OK,否则,返回ERROR。
|
||||
*
|
||||
*【备注】
|
||||
* 教材中i的含义是元素位置,从1开始计数,但这不符合编码的通用约定。
|
||||
* 通常,i的含义应该指索引,即从0开始计数。
|
||||
*/
|
||||
Status GetElem(SqList L, int i, ElemType* e) {
|
||||
// 因为i的含义是位置,所以其合法范围是:[1, length]
|
||||
if(i < 1 || i > L.length) {
|
||||
return ERROR; //i值不合法
|
||||
}
|
||||
|
||||
*e = L.elem[i - 1];
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* ████████ 算法2.4 ████████
|
||||
*
|
||||
* 插入
|
||||
*
|
||||
* 向顺序表第i个位置上插入e,插入成功则返回OK,否则返回ERROR。
|
||||
*
|
||||
*【备注】
|
||||
* 教材中i的含义是元素位置,从1开始计数
|
||||
*/
|
||||
Status ListInsert(SqList* L, int i, ElemType e) {
|
||||
ElemType* newbase;
|
||||
ElemType* p, * q;
|
||||
|
||||
// 确保顺序表结构存在
|
||||
if(L == NULL || (*L).elem == NULL) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// i值越界
|
||||
if(i < 1 || i > (*L).length + 1) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// 若存储空间已满,则增加新空间
|
||||
if((*L).length >= (*L).listsize) {
|
||||
// 基于现有空间扩容
|
||||
newbase = (ElemType*) realloc((*L).elem, ((*L).listsize + LISTINCREMENT) * sizeof(ElemType));
|
||||
if(newbase == NULL) {
|
||||
// 存储内存失败
|
||||
exit(OVERFLOW);
|
||||
}
|
||||
|
||||
// 新基址
|
||||
(*L).elem = newbase;
|
||||
// 存的存储空间
|
||||
(*L).listsize += LISTINCREMENT;
|
||||
}
|
||||
|
||||
// q为插入位置
|
||||
q = &(*L).elem[i - 1];
|
||||
|
||||
// 1.右移元素,腾出位置
|
||||
for(p = &(*L).elem[(*L).length - 1]; p >= q; --p) {
|
||||
*(p + 1) = *p;
|
||||
}
|
||||
|
||||
// 2.插入e
|
||||
*q = e;
|
||||
|
||||
// 3.表长增1
|
||||
(*L).length++;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* ████████ 算法2.5 ████████
|
||||
*
|
||||
* 删除
|
||||
*
|
||||
* 删除顺序表第i个位置上的元素,并将被删除元素存储到e中。
|
||||
* 删除成功则返回OK,否则返回ERROR。
|
||||
*
|
||||
*【备注】
|
||||
* 教材中i的含义是元素位置,从1开始计数
|
||||
*/
|
||||
Status ListDelete(SqList* L, int i, ElemType* e) {
|
||||
ElemType* p, * q;
|
||||
|
||||
// 确保顺序表结构存在
|
||||
if(L == NULL || (*L).elem == NULL) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// i值越界
|
||||
if(i < 1 || i > (*L).length) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// p为被删除元素的位置
|
||||
p = &(*L).elem[i - 1];
|
||||
|
||||
// 1.获取被删除元素
|
||||
*e = *p;
|
||||
|
||||
// 表尾元素位置
|
||||
q = (*L).elem + (*L).length - 1;
|
||||
|
||||
// 2.左移元素,被删除元素的位置上会有新元素进来
|
||||
for(++p; p <= q; ++p) {
|
||||
*(p - 1) = *p;
|
||||
}
|
||||
|
||||
// 3.表长减1
|
||||
(*L).length--;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* 遍历
|
||||
*
|
||||
* 用visit函数访问顺序表L
|
||||
*/
|
||||
void ListTraverse(SqList L, void(Visit)(ElemType)) {
|
||||
int i;
|
||||
|
||||
for(i = 0; i < L.length; i++) {
|
||||
Visit(L.elem[i]);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*=============================
|
||||
* 线性表的顺序存储结构(顺序表)
|
||||
*
|
||||
* 包含算法: 2.3、2.4、2.5、2.6
|
||||
=============================*/
|
||||
|
||||
#ifndef SQLIST_H
|
||||
#define SQLIST_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> // 提供malloc、realloc、free、exit原型
|
||||
#include "Status.h" //**▲01 绪论**//
|
||||
|
||||
/* 宏定义 */
|
||||
#define LIST_INIT_SIZE 100 // 顺序表存储空间的初始分配量
|
||||
#define LISTINCREMENT 10 // 顺序表存储空间的分配增量
|
||||
|
||||
|
||||
/* 顺序表元素类型定义 */
|
||||
typedef void* ElemType;
|
||||
|
||||
/*
|
||||
* 顺序表结构
|
||||
*
|
||||
* 注:elem在使用前需要先为其分配内存,且元素从elem[0]处开始存储
|
||||
*/
|
||||
typedef struct {
|
||||
ElemType* elem; // 顺序表存储空间的基址(指向顺序表所占内存的起始位置)
|
||||
int length; // 当前顺序表长度(包含多少元素)
|
||||
int listsize; // 当前分配的存储容量(可以存储多少元素)
|
||||
} SqList;
|
||||
|
||||
|
||||
/*
|
||||
* ████████ 算法2.3 ████████
|
||||
*
|
||||
* 初始化
|
||||
*
|
||||
* 初始化成功则返回OK,否则返回ERROR。
|
||||
*/
|
||||
Status InitList(SqList* L);
|
||||
|
||||
/*
|
||||
* 计数
|
||||
*
|
||||
* 返回顺序表包含的有效元素的数量。
|
||||
*/
|
||||
int ListLength(SqList L);
|
||||
|
||||
/*
|
||||
* 取值
|
||||
*
|
||||
* 获取顺序表中第i个元素,将其存储到e中。
|
||||
* 如果可以找到,返回OK,否则,返回ERROR。
|
||||
*
|
||||
*【备注】
|
||||
* 教材中i的含义是元素位置,从1开始计数,但这不符合编码的通用约定。
|
||||
* 通常,i的含义应该指索引,即从0开始计数。
|
||||
*/
|
||||
Status GetElem(SqList L, int i, ElemType* e);
|
||||
|
||||
/*
|
||||
* ████████ 算法2.4 ████████
|
||||
*
|
||||
* 插入
|
||||
*
|
||||
* 向顺序表第i个位置上插入e,插入成功则返回OK,否则返回ERROR。
|
||||
*
|
||||
*【备注】
|
||||
* 教材中i的含义是元素位置,从1开始计数
|
||||
*/
|
||||
Status ListInsert(SqList* L, int i, ElemType e);
|
||||
|
||||
/*
|
||||
* ████████ 算法2.5 ████████
|
||||
*
|
||||
* 删除
|
||||
*
|
||||
* 删除顺序表第i个位置上的元素,并将被删除元素存储到e中。
|
||||
* 删除成功则返回OK,否则返回ERROR。
|
||||
*
|
||||
*【备注】
|
||||
* 教材中i的含义是元素位置,从1开始计数
|
||||
*/
|
||||
Status ListDelete(SqList* L, int i, ElemType* e);
|
||||
|
||||
/*
|
||||
* 遍历
|
||||
*
|
||||
* 用visit函数访问顺序表L
|
||||
*/
|
||||
void ListTraverse(SqList L, void (Visit)(ElemType));
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,17 @@
|
||||
| 忑華硊 | 輸湮苤 | 梓祩郖 | ゴЙ硌渀 | 綴樟硌渀 |
|
||||
| :----: | :----: | :----: | :----: | :----: |
|
||||
| 0 | 5 | 1 | -1 | 10 |
|
||||
| 5 | 5 | 0 | -1 | -1 |
|
||||
| 10 | 5 | 1 | 15 | 40 |
|
||||
| 15 | 10 | 1 | -1 | -1 |
|
||||
| 25 | 5 | 0 | -1 | -1 |
|
||||
| 30 | 10 | 0 | -1 | -1 |
|
||||
| 40 | 5 | 1 | 45 | 65 |
|
||||
| 45 | 10 | 1 | -1 | -1 |
|
||||
| 55 | 5 | 0 | -1 | -1 |
|
||||
| 60 | 5 | 0 | -1 | -1 |
|
||||
| 65 | 5 | 1 | 85 | -1 |
|
||||
| 70 | 5 | 0 | -1 | -1 |
|
||||
| 75 | 10 | 0 | -1 | -1 |
|
||||
| 85 | 5 | 1 | 90 | -1 |
|
||||
| 90 | 10 | 1 | -1 | -1 |
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 55 KiB |
Binary file not shown.
@@ -289,6 +289,16 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "07.41", "07.41\07.41.vcxpro
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "07.42", "07.42\07.42.vcxproj", "{80E94E2F-B06C-4B8B-9B6C-88F9FE66B09B}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "08.11-08.12", "08.11-08.12\08.11-08.12.vcxproj", "{92D19D62-5A91-436F-BCAC-672018B7B67B}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "08.13", "08.13\08.13.vcxproj", "{B8418DCB-E6A4-4C39-97FC-E57B694A4512}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "08.14", "08.14\08.14.vcxproj", "{5CA72478-69D3-4ECB-A4FC-C4F3B9B9E370}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "08.15", "08.15\08.15.vcxproj", "{597EDEF1-E7A2-4CCB-A036-13D81A98F053}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "08.16", "08.16\08.16.vcxproj", "{BFA3C1E2-BC09-4DF8-AB69-680C5EE9A7B1}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
@@ -871,6 +881,26 @@ Global
|
||||
{80E94E2F-B06C-4B8B-9B6C-88F9FE66B09B}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{80E94E2F-B06C-4B8B-9B6C-88F9FE66B09B}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{80E94E2F-B06C-4B8B-9B6C-88F9FE66B09B}.Release|Win32.Build.0 = Release|Win32
|
||||
{92D19D62-5A91-436F-BCAC-672018B7B67B}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{92D19D62-5A91-436F-BCAC-672018B7B67B}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{92D19D62-5A91-436F-BCAC-672018B7B67B}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{92D19D62-5A91-436F-BCAC-672018B7B67B}.Release|Win32.Build.0 = Release|Win32
|
||||
{B8418DCB-E6A4-4C39-97FC-E57B694A4512}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{B8418DCB-E6A4-4C39-97FC-E57B694A4512}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{B8418DCB-E6A4-4C39-97FC-E57B694A4512}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{B8418DCB-E6A4-4C39-97FC-E57B694A4512}.Release|Win32.Build.0 = Release|Win32
|
||||
{5CA72478-69D3-4ECB-A4FC-C4F3B9B9E370}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{5CA72478-69D3-4ECB-A4FC-C4F3B9B9E370}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{5CA72478-69D3-4ECB-A4FC-C4F3B9B9E370}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{5CA72478-69D3-4ECB-A4FC-C4F3B9B9E370}.Release|Win32.Build.0 = Release|Win32
|
||||
{597EDEF1-E7A2-4CCB-A036-13D81A98F053}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{597EDEF1-E7A2-4CCB-A036-13D81A98F053}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{597EDEF1-E7A2-4CCB-A036-13D81A98F053}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{597EDEF1-E7A2-4CCB-A036-13D81A98F053}.Release|Win32.Build.0 = Release|Win32
|
||||
{BFA3C1E2-BC09-4DF8-AB69-680C5EE9A7B1}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{BFA3C1E2-BC09-4DF8-AB69-680C5EE9A7B1}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{BFA3C1E2-BC09-4DF8-AB69-680C5EE9A7B1}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{BFA3C1E2-BC09-4DF8-AB69-680C5EE9A7B1}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user