为避免低址部分留下许多很小的空间分区,以及减少查找可用空闲分区的开销,循环首次适应算法在为进程分配内存空间时,不再是每次都从链首开始查找,而是从上次找到的空闲分区的下一个空闲分区开始查找,直至找到一个能满足要求的空闲分区,从中划出一块与请求大小相等的内存空间分配给作业。
为实现该算法,应该设置起始查寻指针,用于指示下一次起始查寻的空闲分区,并采用循环查找方式,即如果最后一个(链尾)空闲分区的大小仍不能满足要求,则应该返回到第一个空闲分区,比较其大小是否满足要求。找到后,应该调整起始查寻指针。
a) 在进行NF之前应该先初始化一条空闲分区链;
空闲分区链结构体:
typedef struct free_excel {
int number; //分区号
double begin_address; //起始地址
double scale; //长度
int partition_status; //分区状态
struct free_excel * next;
} Sqfree_ex, *Sqfree;
b) 当作业申请内存空间时应该为从起始查寻指针开始查找到可以为其分配内存空间的内存大小,如果所找到的内存空间大小-作业所申请的内存空间大小>分割阈值为0.3k,则需要将所找到的内存空间大小进行再次分割,反之则直接将该内存空间分配给该作业。如果找不到一个内存空间大小可以满足该作业,则认为对其的分配失败。
在具体的实现中,利用链表来表示空闲分区,利用另一链表来存放已经分配内存空闲大小的作业,每进行分配的时候,分配成功将该作业存放到已分配内存空间的链表中,每当作业完成后,将作业从该链表中移除。
用一指针来记录开始的查询地址,这一查寻指针是从头结点开始的,每次去判断下一个地址是否能够分配给作业。因为头结点是不存放内存空间大小的,因为设置的是单向链表因此这样做有一个好处便是如果找到了一个可以分配的且分割阈值<0.3的内存空间大小,那么就可以将该内存中链表中去除,否则的话还需要去寻找它的前一个结点才能够将该内存空间删除。即判断下个,判断分割阈值<0.3成功,删除下个;对于单向链表而言,判断当前,删除当前是较麻烦的。
c) 当该作业完成后需要对该作业的内存空间大小进行回收
回收的过程比较复杂,分为4种情况:
i. 回收分区与插入点的前一个空闲分区相邻接,此时应该将回收区与插入点的前一个分区合并,不必为回收分区分配新表项,而只需要修改其前一个分区的大小。
ii. 回收分区与插入点的后一空闲分区相邻接。此时也可以将两分区合并,而形成新的空闲分区,但用回收区的首地址作为新空闲区的首址,大小为两者之和。
iii. 回收区同时与插入点的前、后两个分区邻接,此时三个分区合并,使用在这三个分区种的第一个分区的表项和首地址,取消在这三个分区中的最后一个表项,大小为原本空闲链表中的两个分区之和+需要回收的内存空间大小。
iv. 回收区不和任何一个分区相邻接,这是应该为回收区单独建立一个新表项,填写回收区的首址和大小,并根据其首址插入到空闲链中的适当位置。
在具体代码实现中,分成了三种情况,对第一个非头结点分区进行考虑、对尾结点分区进行考虑、对除上述两种结点进行考虑。对第一个非头结点进行考虑时,只需要回收区的末尾能否和第一个非头结点分区相邻接,对尾结点分区进行考虑时,只需要考虑尾结点的末尾能否与回收分区的首址相邻接,而对除上述两种结点分区进行考虑时,就需要考虑上述所言的4种情况。
int NF(Sqfree &s, job &j, Sqjob &ljob) { //循环首次适应
Sqfree begin = flag;
for (int i = 0; i < Sqfree_sum; i++) {
if (begin->next != NULL && begin->next->scale >= j.request) {
if (begin->next->scale - j.request > limit) { //所剩下的太大,还需要分区
j.begin_address = begin->next->begin_address;
j.end_address = begin->next->begin_address + j.request;
begin->next->begin_address = begin->next->begin_address + j.request;
begin->next->partition_status = 1;
begin->next->scale = begin->next->scale - j.request;
insert_Sqjob(ljob , j);
flag = begin;
cout << "分配成功" << endl;
return 1;}
else if (begin->next->scale - j.request <= limit) {
j.begin_address = begin->next->begin_address;
j.end_address = j.begin_address + begin->next->scale;
begin->next = begin->next->next;
Sqfree_sum--;
insert_Sqjob(ljob , j);
flag = begin;
cout << "分配成功" << endl;
return 1;
}
}
else if (begin->next == NULL){
begin = s;
}
else {
begin = begin->next;
}
}
cout << "分配失败" << endl;
return 0;
}
void delete_job(Sqjob &ljob, Sqjob j) { //从作业已分配中将该作业去除
Sqjob head = ljob;
while ( head != NULL){
if ( head->next == j) {
head->next = head->next->next;
}
head = head->next;
}
}
int recovery(Sqfree &s, Sqjob &ljob) {
sortSqfree_bgadd(s);
Sqfree pre = s;
Sqfree head = s->next;
Sqjob temp = recovery_job(ljob);
if (temp != NULL) {
while (head != NULL)
{
if (head == s->next) { //如果是第一个结点考虑他之前的情况即可
if (head->begin_address > temp->end_address) { //在它前面直接增加一个结点
Sqfree newnode = (Sqfree)malloc(sizeof(Sqfree_ex));
newnode->begin_address = temp->begin_address;
newnode->partition_status = 1;
newnode->scale = temp->begin_address - temp->end_address;
newnode->number=++Sqfree_number;
newnode->next = head;
s->next = newnode;
Sqfree_sum++;
break;
} else if (head->begin_address == temp->end_address) { //刚好可以与前面连接
head->begin_address = temp->begin_address;
head->scale = head->scale + temp->end_address - temp->begin_address;
break;
}
} else if(pre != s) {
if (pre->begin_address + pre->scale == temp->begin_address&&head->begin_address==temp->end_address) {
pre->scale = pre->scale + temp->end_address - temp->begin_address + head->scale;
pre->next = head->next;
Sqfree_sum--;
break;
} else if (pre->begin_address + pre->scale == temp->begin_address) {
pre->scale = pre->scale + temp->end_address - temp->begin_address;
break;
} else if (head->begin_address == temp->end_address) {
head->begin_address = temp->begin_address;
head->scale = head->scale + temp->end_address - temp->begin_address;
break;
} else if (pre->begin_address + pre->scale<temp->begin_address && temp->end_address<head->begin_address) {
Sqfree newnode = (Sqfree)malloc(sizeof(Sqfree_ex));
newnode->begin_address = temp->begin_address;
newnode->partition_status = 1;
newnode->scale = temp->begin_address - temp->end_address;
newnode->number=++Sqfree_number;
newnode->next = head;
pre->next = newnode;
Sqfree_sum++;
break;
}
} else if (head->next == NULL) {
if (head->begin_address + head->scale == temp->begin_address) {
head->scale = head->scale + temp->end_address - temp->begin_address;
break;
} else {
Sqfree newnode = (Sqfree)malloc(sizeof(Sqfree_ex));
newnode->begin_address = temp->begin_address;
newnode->partition_status = 1;
newnode->scale = temp->begin_address - temp->end_address;
newnode->number=++Sqfree_number;
newnode->next = head->next;
head->next = newnode;
Sqfree_sum++;
break;
}
}
head = head->next;
pre = pre->next;
}
delete_job(ljob, temp);
} else {
cout << "找不到该作业,无法回收" << endl;
}
return 0;
}
由于最坏适应算法选择空闲分区的策略正好与最佳适应算法相反:它在扫描整个空闲分区表或链表时,总是挑选一个最大的空闲区,从中分割一部分存储空间给作业使用,以至于存储器中缺乏大的空闲分区,故把它称为是最坏适应算法。
最坏适应分配算法只需要将所有的空闲分区,按其容量从大到小的顺序形成一空闲分区链,只要看第一个分区能否满足作业要求即可。
a) 在进行WF和NF一样都应该先初始化一条空闲分区链;
空闲分区链结构体:
typedef struct free_excel {
int number; //分区号
double begin_address; //起始地址
double scale; //长度
int partition_status; //分区状态
struct free_excel * next;
} Sqfree_ex, *Sqfree;
b) 当作业要进行申请内存空间大小时,应该先将空闲分区链按照容量从大到小进行排序,
为实现该过程,设置了一个变量用来记录空闲分区链中的非头结点数量。记录了空闲分区链中的非头结点数量后,就可以利用冒泡法进行排序。
因为在输出时,将地址按照从小到大输出更为好看,因此也编写了一个函数,该函数用于将空闲链表从小到大输出,也是采用冒泡法进行操作。
c) 进行内存分配,每次只需要判断第一个非头结点是否能够分配给申请内存空闲大小的作业即可。如果所找到的内存空间大小-作业所申请的内存空间大小>分割阈值为0.3k,则需要将所找到的内存空间大小进行再次分割,反之则直接将该内存空间分配给该作业。如果第一个非头结点内存空间大小可以满足该作业,则认为对其的分配失败。
d) 当该作业完成后需要对该作业的内存空间大小进行回收,该过程和NF的过程一样
回收的过程比较复杂,分为4种情况:
v. 回收分区与插入点的前一个空闲分区相邻接,此时应该将回收区与插入点的前一个分区合并,不必为回收分区分配新表项,而只需要修改其前一个分区的大小。
vi. 回收分区与插入点的后一空闲分区相邻接。此时也可以将两分区合并,而形成新的空闲分区,但用回收区的首地址作为新空闲区的首址,大小为两者之和。
vii. 回收区同时与插入点的前、后两个分区邻接,此时三个分区合并,使用在这三个分区种的第一个分区的表项和首地址,取消在这三个分区中的最后一个表项,大小为原本空闲链表中的两个分区之和+需要回收的内存空间大小。
viii. 回收区不和任何一个分区相邻接,这是应该为回收区单独建立一个新表项,填写回收区的首址和大小,并根据其首址插入到空闲链中的适当位置。
在具体代码实现中,分成了三种情况,对第一个非头结点分区进行考虑、对尾结点分区进行考虑、对除上述两种结点进行考虑。对第一个非头结点进行考虑时,只需要回收区的末尾能否和第一个非头结点分区相邻接,对尾结点分区进行考虑时,只需要考虑尾结点的末尾能否与回收分区的首址相邻接,而对除上述两种结点分区进行考虑时,就需要考虑上述所言的4种情况。
由于分区回收的代码和NF是一样的,因此在这里不在列出来。
int WF_allocation(Sqfree &s, Sqjob &ljob, job &j) {
sortSqfree_scale(s);
Sqfree head = s;
if (head->next->scale >= j.request) {
if (head->next->scale - j.request > limit) { //需要对内存空间再分割
j.begin_address = head->next->begin_address;
head->next->scale = head->next->scale - j.request;
head->next->begin_address = head->next->begin_address + j.request;
j.end_address = j.begin_address + j.request;
insert_Sqjob(ljob,j);
cout << "分配成功" << endl;
return 1;
} else { //无需对内存空间再分割
j.begin_address = head->next->begin_address;
j.end_address = head->next->begin_address + head->next->scale;
head->next = head->next->next;
insert_Sqjob(ljob, j);
Sqfree_sum--;
cout << "分配成功" << endl;
return 1;
}
}
cout << "分配失败" << endl;
return 0;
}
void sortSqfree_scale(Sqfree& s) { //根据内存大小进行排序
Sqfree head = s->next;
for (int j = 0; j < Sqfree_sum - 1; j++) { //冒泡排序从大到小
head = s->next;
for (int i = 0; i < Sqfree_sum - 1 - j; i++) {
if (head->scale < head->next->scale) {
Sqfree_ex temp;
temp.scale = head->scale;
temp.begin_address = head->begin_address;
temp.partition_status = head->partition_status;
temp.number = head->number;
head->scale = head->next->scale;
head->begin_address = head->next->begin_address;
head->partition_status = head->next->partition_status;
head->number = head->next->number;
head->next->scale = temp.scale;
head->next->begin_address = temp.begin_address;
head->next->partition_status = temp.partition_status;
head->next->number = temp.number;
}
head = head->next;
}
}
}
void sortSqfree_bgadd(Sqfree &s) { //根据起始地址对空闲链表进行排序
Sqfree head = s->next;
for (int j = 0; j < Sqfree_sum - 1; j++) { //冒泡排序从小到大
head = s->next;
for (int i = 0; i < Sqfree_sum - 1 - j; i++) {
if (head->begin_address > head->next->begin_address) {
Sqfree_ex temp;
temp.scale = head->scale;
temp.begin_address = head->begin_address;
temp.partition_status = head->partition_status;
temp.number = head->number;
head->scale = head->next->scale;
head->begin_address = head->next->begin_address;
head->partition_status =head->next->partition_status;
head->number = head->next->number;
head->next->scale = temp.scale;
head->next->begin_address = temp.begin_address;
head->next->partition_status = temp.partition_status;
head->next->number = temp.number;
}
head = head->next;
}
}
}
完整代码如下:
可根据需求自行修改分配的次数和回收的次数:
#include
#include
using namespace std;
typedef struct free_excel {
int number; //分区号
double begin_address; //起始地址
double scale; //长度
int partition_status; //分区状态
struct free_excel * next;
} Sqfree_ex, *Sqfree;
typedef struct job {
double request; //请求资源空间
string name; //作业/进程名
double begin_address; //首地址
double end_address;
struct job* next;
}job, *Sqjob;
static Sqfree flag; //标记指针;
#define limit 0.3
static int number = 6;
static int Sqfree_number = 6; //空闲链表分区的编号最少从6开始
static int Sqfree_sum = 6; //空闲链表中的数量
int init_Sqfree(Sqfree &s) { //初始化空闲链表
Sqfree head = (Sqfree)malloc(sizeof(Sqfree_ex));
if (head != NULL) {
s = head;
head->next = NULL;
return 1;
} else {
return 0;
}
}
int init_Sqjob(Sqjob& ljob); //初始化分配空间的作业链
void insert_Sqjob(Sqjob& ljob, job& j); //尾插法
void insert_Sqfree(Sqfree& s, Sqfree_ex excel[6]); //初始化空闲分区表
void print_Sqfree(Sqfree s); //输出空闲分区链
void WF_init(Sqfree s, Sqfree_ex excel[6]); //最坏适应算法初始化将链表按从大到小排
int WF_allocation(Sqfree& s, Sqjob& ljob, job& j); //WF
void sortSqfree_bgadd(Sqfree& s); //根据起始地址对空闲链表进行排序
void sortSqfree_scale(Sqfree& s); //根据内存大小进行排序
Sqjob recovery_job(Sqjob& ljob); //回收内存输入
void delete_job(Sqjob& ljob, Sqjob j); //从作业已分配中将该作业去除
int recovery(Sqfree& s, Sqjob& ljob); //内存回收
void init_job(job& j);
void print_Sqjob(Sqjob ljob);
int NF(Sqfree& s, job& j, Sqjob& ljob); //循环首次适应
int init_Sqjob(Sqjob &ljob) {
Sqjob head = (Sqjob)malloc(sizeof(job));
if (head != NULL) {
ljob = head;
head->next = NULL;
return 1;
} else
{
return 0;
}
}
void insert_Sqjob(Sqjob& ljob, job &j) {
Sqjob head = ljob;
Sqjob temp;
while (head->next != NULL) {
head = head->next;
}
temp = &j;
temp->next = head->next;
head->next = temp;
}
void insert_Sqfree(Sqfree &s, Sqfree_ex excel[6]) {
Sqfree head = s;
Sqfree temp;
for (int i = 0; i < 6; i++){
temp = &excel[i];
temp->next = head->next;
head->next = temp;
head = head->next;
}
}
void print_Sqfree(Sqfree s) {
sortSqfree_bgadd(s);
Sqfree head = s->next;
cout << "分区号" <<'\t'<<'\t'<< "起始地址" << '\t' << "长度" <<'\t'<<'\t'<< "状态" << endl;
while (head != NULL) {
cout << head->number<<'\t'<<'\t'<<head->begin_address<<'\t'<<'\t'<<head->scale<<'\t'<<'\t';
if (head->partition_status == 1) {
cout << "空闲" << endl;
}
else {
cout << "已分配" << endl;
}
head = head->next;
}
}
void WF_init(Sqfree s, Sqfree_ex excel[6]) {
Sqfree head = s;
Sqfree temp;
for (int j = 0; j < 6 - 1; j++) { //冒泡排序从小到大
for (int i = 0; i < 6 - 1 - j; i++) {
if (excel[i].scale < excel[i + 1].scale) {
Sqfree_ex temp;
temp = excel[i];
excel[i] = excel[i + 1];
excel[i + 1] = temp;
}
}
}
for (int i = 0; i < 6; i++) {
temp = &excel[i];
temp->next = head->next;
head->next = temp;
head = head->next;
}
}
int WF_allocation(Sqfree &s, Sqjob &ljob, job &j) {
sortSqfree_scale(s);
Sqfree head = s;
if (head->next->scale >= j.request) {
if (head->next->scale - j.request > limit) { //需要对内存空间再分割
j.begin_address = head->next->begin_address;
head->next->scale = head->next->scale - j.request;
head->next->begin_address = head->next->begin_address + j.request;
j.end_address = j.begin_address + j.request;
insert_Sqjob(ljob,j);
cout << "分配成功" << endl;
return 1;
} else { //无需对内存空间再分割
j.begin_address = head->next->begin_address;
j.end_address = head->next->begin_address + head->next->scale;
head->next = head->next->next;
insert_Sqjob(ljob, j);
Sqfree_sum--;
cout << "分配成功" << endl;
return 1;
}
}
cout << "分配失败" << endl;
return 0;
}
void sortSqfree_bgadd(Sqfree &s) {
Sqfree head = s->next;
for (int j = 0; j < Sqfree_sum - 1; j++) { //冒泡排序从小到大
head = s->next;
for (int i = 0; i < Sqfree_sum - 1 - j; i++) {
if (head->begin_address > head->next->begin_address) {
Sqfree_ex temp;
temp.scale = head->scale;
temp.begin_address = head->begin_address;
temp.partition_status = head->partition_status;
temp.number = head->number;
head->scale = head->next->scale;
head->begin_address = head->next->begin_address;
head->partition_status =head->next->partition_status;
head->number = head->next->number;
head->next->scale = temp.scale;
head->next->begin_address = temp.begin_address;
head->next->partition_status = temp.partition_status;
head->next->number = temp.number;
}
head = head->next;
}
}
}
void sortSqfree_scale(Sqfree& s) {
Sqfree head = s->next;
for (int j = 0; j < Sqfree_sum - 1; j++) { //冒泡排序从小到大
head = s->next;
for (int i = 0; i < Sqfree_sum - 1 - j; i++) {
if (head->scale < head->next->scale) {
Sqfree_ex temp;
temp.scale = head->scale;
temp.begin_address = head->begin_address;
temp.partition_status = head->partition_status;
temp.number = head->number;
head->scale = head->next->scale;
head->begin_address = head->next->begin_address;
head->partition_status = head->next->partition_status;
head->number = head->next->number;
head->next->scale = temp.scale;
head->next->begin_address = temp.begin_address;
head->next->partition_status = temp.partition_status;
head->next->number = temp.number;
}
head = head->next;
}
}
}
Sqjob recovery_job(Sqjob &ljob) {
string temp;
cout << "请输入要回收的作业:";
cin >> temp;
Sqjob head = ljob->next;
while (head != NULL){
if (head->name == temp){
return head;
}
head = head->next;
}
return NULL;
}
void delete_job(Sqjob &ljob, Sqjob j) {
Sqjob head = ljob;
while ( head != NULL){
if ( head->next == j) {
head->next = head->next->next;
}
head = head->next;
}
}
int recovery(Sqfree &s, Sqjob &ljob) {
sortSqfree_bgadd(s);
Sqfree pre = s;
Sqfree head = s->next;
Sqjob temp = recovery_job(ljob);
if (temp != NULL) {
while (head != NULL)
{
if (head == s->next) { //如果是第一个结点考虑他之前的情况即可
if (head->begin_address > temp->end_address) { //在它前面直接增加一个结点
Sqfree newnode = (Sqfree)malloc(sizeof(Sqfree_ex));
newnode->begin_address = temp->begin_address;
newnode->partition_status = 1;
newnode->scale = temp->begin_address - temp->end_address;
newnode->number=++Sqfree_number;
newnode->next = head;
s->next = newnode;
Sqfree_sum++;
break;
} else if (head->begin_address == temp->end_address) { //刚好可以与前面连接
head->begin_address = temp->begin_address;
head->scale = head->scale + temp->end_address - temp->begin_address;
break;
}
} else if(pre != s) {
if (pre->begin_address + pre->scale == temp->begin_address&&head->begin_address==temp->end_address) {
pre->scale = pre->scale + temp->end_address - temp->begin_address + head->scale;
pre->next = head->next;
Sqfree_sum--;
break;
} else if (pre->begin_address + pre->scale == temp->begin_address) {
pre->scale = pre->scale + temp->end_address - temp->begin_address;
break;
} else if (head->begin_address == temp->end_address) {
head->begin_address = temp->begin_address;
head->scale = head->scale + temp->end_address - temp->begin_address;
break;
} else if (pre->begin_address + pre->scale<temp->begin_address && temp->end_address<head->begin_address) {
Sqfree newnode = (Sqfree)malloc(sizeof(Sqfree_ex));
newnode->begin_address = temp->begin_address;
newnode->partition_status = 1;
newnode->scale = temp->begin_address - temp->end_address;
newnode->number=++Sqfree_number;
newnode->next = head;
pre->next = newnode;
Sqfree_sum++;
break;
}
} else if (head->next == NULL) {
if (head->begin_address + head->scale == temp->begin_address) {
head->scale = head->scale + temp->end_address - temp->begin_address;
break;
} else {
Sqfree newnode = (Sqfree)malloc(sizeof(Sqfree_ex));
newnode->begin_address = temp->begin_address;
newnode->partition_status = 1;
newnode->scale = temp->begin_address - temp->end_address;
newnode->number=++Sqfree_number;
newnode->next = head->next;
head->next = newnode;
Sqfree_sum++;
break;
}
}
head = head->next;
pre = pre->next;
}
delete_job(ljob, temp);
} else {
cout << "找不到该作业,无法回收" << endl;
}
return 0;
}
void init_job(job &j) {
cout << "请输入作业名" << endl;
cin >> j.name;
cout << "请输入请求的内存空间" << endl;
cin >> j.request;
}
void print_Sqjob(Sqjob ljob) {
Sqjob head = ljob->next;
while (head != NULL) {
cout << "作业名:" << head->name<<'\t'<<"申请内存空间:"<<head->request<<'\t'<<"开始地址:"<<head->begin_address<<'\t'
<<"结束地址:"<<head->end_address<<endl;
head = head->next;
}
}
int NF(Sqfree &s, job &j, Sqjob &ljob) {
Sqfree begin = flag;
for (int i = 0; i < Sqfree_sum; i++) {
if (begin->next != NULL && begin->next->scale >= j.request) {
if (begin->next->scale - j.request > limit) { //所剩下的太大,还需要分区
j.begin_address = begin->next->begin_address;
j.end_address = begin->next->begin_address + j.request;
begin->next->begin_address = begin->next->begin_address + j.request;
begin->next->partition_status = 1;
begin->next->scale = begin->next->scale - j.request;
insert_Sqjob(ljob , j);
flag = begin;
cout << "分配成功" << endl;
return 1;}
else if (begin->next->scale - j.request <= limit) {
j.begin_address = begin->next->begin_address;
j.end_address = j.begin_address + begin->next->scale;
begin->next = begin->next->next;
Sqfree_sum--;
insert_Sqjob(ljob , j);
flag = begin;
cout << "分配成功" << endl;
return 1;
}
}
else if (begin->next == NULL){
begin = s;
}
else {
begin = begin->next;
}
}
cout << "分配失败" << endl;
return 0;
}
int main() {
Sqfree_ex excel[6] = {
{1, 0, 10, 1, NULL},
{2, 10, 18, 1, NULL},
{3, 28, 16, 1, NULL},
{4, 44, 6, 1, NULL},
{5, 50, 21, 1, NULL},
{6, 71, 30, 1, NULL}};
Sqfree s;
job j1;
job j2;
job j3;
Sqjob ljob;
//初始化
cout << "初始化空闲分区表" << endl;
init_Sqjob(ljob);
init_Sqfree(s);
insert_Sqfree(s, excel);
print_Sqfree(s);
flag = s;
//开始进行WF处理
cout << "----WF----" << endl;
init_job(j1);
WF_allocation(s, ljob, j1);
print_Sqfree(s);
//第二次进行WF处理
init_job(j2);
WF_allocation(s, ljob, j2);
print_Sqfree(s);
//回收
recovery(s, ljob);
print_Sqfree(s);
//第三次进行WF处理
init_job(j3);
WF_allocation(s, ljob, j3);
print_Sqfree(s);
print_Sqjob(ljob);
//NF测试,将下述注释取消即可
//cout << "----NF----" << endl;
//init_job(j1);
//NF(s , j1 , ljob);
//print_Sqfree(s);
//init_job(j2);
//NF(s, j2, ljob);
//print_Sqfree(s);
//recovery(s , ljob);
//print_Sqfree(s);
//init_job(j3);
//NF(s , j3, ljob);
//print_Sqfree(s);
//print_Sqjob(ljob);
return 0;
}