Partition List 二分链表(重)

该博客详细解析了LeetCode中的Partition List问题,通过类似快速排序的二分思想,对链表进行重新排列。讨论了如何处理头尾节点的关键细节,并提供了实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:

点击打开链接

解答:

类似于快排的二分,注意头尾节点,


代码:

class Solution {
public:
	ListNode *partition(ListNode *head, int x) {
		ListNode *little, *large;
		ListNode *largeHead = NULL;
		ListNode *littleHead = NULL;
		little = large = NULL;
		ListNode *temp = head;
		while (temp)
		{
			if (temp->val < x)
			{
				//头结点
				if (little == NULL)
				{
					little = temp;
					littleHead = little;
				}
				else
				{
					little->next = temp;
					little = little->next;
				}
			}
			else
			{
				//头结点
				if (large == NULL)
				{
					large = temp;
					largeHead = large;
				}
				else
				{
					large->next = temp;
					large = large->next;
				}
			}
			temp = temp->next;
		}
		//如果large存在 尾节点后置空
		if(large)
			large->next = NULL;
		//如果little存在 尾节点后置为largeHead
		if (little)
			little->next = largeHead;
		//如果小于哨兵的链表不存在 返回large链表
		if(littleHead == NULL)
			return largeHead;
		//否则返回little链表
		return littleHead;
	}
};


设计步骤 2.3.1 数据结构分析 为了实现存储资源的分配和回收,操作系统需要记录内存资源使用情况,即哪些区域尚未分配,哪些区域已经分配以及分配给哪些进程等。为此一般需要两个表,一个为分配表, 另外一个为空闲区域表。前者记录已经分配的区域, 后者记录着所有当前未被进程占用的空闲区域, 如图2-1所示。 显然, 没有记录于表中的区域即为已被进程所占用的非空闲区域,在实际的操作系统中,这些区域登记在进程的PCB中。而PCB中除了关于内存资源的信息外,还有其它大量信息。 由于本设计是对存储管理算法的模拟,所以用一个线程来代表一个进程,用线程驻留区域表来描述线程占用的内存空间,如图2-2所示。 线程名称 驻留区始址 驻留区大小 a 0 10 b 20 20 …… …… …… 图2-2 线程驻留区表 同时,需要一张表来记录各个线程对内存的请求信息,如图2-3所示。 线程名称 请求大小(KB) 预计驻留时间() thread_1 20 4 thread_2 10 5 …… …… …… 图2-3 内存申请表 2.3.2 算法分析 分配时取满足申请要求且长度最小的空闲区域。在实现时, 可将系统中所有的空闲区域按照长度由小到大的次序依次记录于空闲区域表中。与最先适应算法相类似, 当进程申请存储空间时, 系统由表的头部开始查找, 取第一个满足要求的表目。如果该表目所对应的区域长度恰好与所申请的区域长度相同, 则将该区域全部分配给申请者。否则将该区域分割为两部分, 一部分的长度与所申请的长度相同, 将其分配给申请者;另一部分即剩余部分的长度为原长度与分配长度之差, 由于剩余部分的长度已经改变,所以应新将其按长度从小到大的顺序插入到空闲区域表中。 回收时,不仅要按回收区的首地址查询空闲区表,找到与回收区相临的空闲区,将其合并到相临区中,而且要把合并后的回收区按照长度递增的顺序插入到空闲区域表的适当位置。 2.3.3 设计并分析测试数据 假设初始内存布局如图2-4,图中的起始地址以及大小都以KB来衡量。 起始地址 0 10 20 40 70 80 85 145 160 180 占用者 a b c d e 大 小 10 10 20 30 10 5 60 15 20 20 图2-4初始内存布局 由图2-4可见,初始时共有五个线程驻留在内存,它们是a,b,c,d,e,线程驻留区表如图2-5;还有五个空闲区,空闲区域表如图2-6。 假设现在有三个线程提出内存申请,申请情况见图2-7。经过分析我们得到在每种分配算法下这三个线程所申请到的内存情况。图2-8是最佳适应算法分配情况。 2.3.4 程序设计 程序包含两个文件,一个是头文件variable_partition.h,另一个是源程序文件variable_partition.cpp。在头文件中定义了宏、数据结构、全局变量、函数声明,源程序中含有各个函数的实现。 在头文件中,结构体FREEAREA、REQUIRE_MEMORY、THREAD_RESIDENCE_MEMORY分别对应于图2-1、图2-2、图2-3中的一行,不同之处是为了构成链表在三个结构体中都有前向指针。数组init_free_area_table对应于图2-6,数组init_thread_require_memory_table对应于图2-5,数组init_thread_residence_memory_table对应于图2-7,为了实现动态分配与释放,用链表新组织空闲区域表、线程驻留区表和内存申请表,全局变量p_free_area_list是空闲区链首,p_thread_require_memory_queue是内存申请队列的队首,p_thread_residence_memory_list是线程驻留区链首,tail_thread_residence_memory_list是线程驻留区链尾,由于线程驻留区链表被内存分配函数和内存释放函数共享,故用临界区变量CS_THREAD_MEMORY_LIST来保护,同理,屏幕是所有线程共享的,所以用临界区变量CS_SCREEN来保护,空闲区链表被内存分配函数和内存释放函数共享,故用临界区变量CS_FREEAREA_LIST来保护。h_thread是线程句柄数组,用来存放各个线程的句柄。 程序共包含13个函数,按照作用可以将它们分成五组。 第一组包括函数print_space()和函数display_thread_residence_memory(),前者用来显示若干个空格,后者用来显示线程驻留区表; 第二组共十一个函数,用来实现最佳适应分配法,它们的名称及功能如图2-9。 函数名称 函数功能 BF_initialize_freearea_list 初始化空闲区链表:按长度递增排序 BF_delete_freearea_list 删除空闲区链表 BF_initialize_require_memory_list 初始化内存申请链表 BF_delete_require_memory_list 删除内存申请链表 BF_initialize_thread_residence_memory_list 初始化线程驻留区链表 BF_delete_thread_residence_memory_list 删除线程驻留区链表 BF_thread 线程函数:申请内存;驻留内存;释放内存 BF_require_memory 申请一段内存,成功时返回起始地址,失败时返回空 BF_release_memory 释放一段内存 BF_insert_freearea 将空闲区按大小递增的次序插入到空闲区链表中 BF() 初始化函数:创建线程并等待它们结束 图2-9 最佳适应分配法的函数及其功能 2.3.5 参考源代码 下面是部分程序的源代码清单。 头文件 variable_partition.h 的清单 #include <windows.h> #include <conio.h> #include <stdlib.h> #include <stdio.h> #include <io.h> #include <string.h> #define MAX_THREAD 3 typedef struct freearea{ //表示空闲区域的数据结构 struct freearea *next; //指向下一个结点的指针 int start_address; //空闲区起始地址 int size; //空闲区大小 }FREEAREA; typedef struct require_memory{ //记录线程申请内存的数据结构 struct require_memory *next; //指向下一个结点的指针 char thread_name[10]; //线程名 int size; //申请内存大小(以KB为单位) int duration; //在内存的驻留时间(以秒为单位) }REQUIRE_MEMORY; typedef struct thread_residence_memory{ //描述线程驻留区的数据结构 struct thread_residence_memory *next; //指向下一个结点的指针 char thread_name[10]; //线程名 int start_address; //驻留区起始地址 int size; //驻留区大小 }THREAD_RESIDENCE_MEMORY; FREEAREA init_free_area_table[5]={ {NULL,10,10}, {NULL,40,30}, {NULL,80,5}, {NULL,145,15}, {NULL,180,20} }; //测试数据:初始空闲区表 REQUIRE_MEMORY init_thread_require_memory_table[3]={ {NULL,"thread_1",20,4}, {NULL,"thread_2",10,5}, {NULL,"thread_3",5,6} }; //测试数据:初始内存申请表 THREAD_RESIDENCE_MEMORY init_thread_residence_memory_table[5]={ {NULL,"a",0,10}, {NULL,"b",20,20}, {NULL,"c",70,10}, {NULL,"d",85,60}, {NULL,"e",160,20} };//测试数据:初始线程驻留区表 FREEAREA *p_free_area_list=NULL; //空闲区链首 REQUIRE_MEMORY *p_thread_require_memory_queue=NULL; //内存申请队列队首 THREAD_RESIDENCE_MEMORY *p_thread_residence_memory_list=NULL; //线程驻留链首 THREAD_RESIDENCE_MEMORY *tail_thread_residence_memory_list=NULL; //线程驻留区链尾 CRITICAL_SECTION CS_THREAD_MEMORY_LIST; //保护线程驻留区链表的临界区 CRITICAL_SECTION CS_SCREEN; //保护屏幕的临界区 CRITICAL_SECTION CS_FREEAREA_LIST; //保护空闲区链表的临界区 HANDLE h_thread[MAX_THREAD]; //线程句柄数组 void print_space(int num); //输出若干个空格 void display_thread_residence_memory_list(); //显示线程驻留区表 //最佳适应分配算法的函数 void BF_thread(void *data); //线程函数 void BF_delete_freearea_list(); //删除空闲区链表 REQUIRE_MEMORY *BF_initialize_require_memory_list(REQUIRE_MEMORY *init_table,int num); //初始化内存申请链表 void BF_delete_require_memory_list(); //删除内存申请链表 THREAD_RESIDENCE_MEMORY *BF_initialize_thread_residence_memory_list (THREAD_RESIDENCE_MEMORY *init_table,int num); //初始化线程驻留区链表 void BF_delete_thread_residence_memory_list(); //删除线程驻留区链表 int BF_require_memory(int size); //内存申请函数 void BF_release_memory(int start_address,int size); //内存释放函数 void BF_insert_freearea(FREEAREA *free_node); //空闲区结点插入函数 void BF(); //初始化程序 void BF_initialize_freearea_list(FREEAREA *init_table,int num); //初始化空闲区链表 源程序文件 variable_partition.cpp 的清单 #include "variable_partition.h" void print_space(int num){ //显示若干个空格 int i; for(i=0;i<num;i++){ printf(" "); } } void display_thread_residence_memory_list(){ //显示驻留线程链表 THREAD_RESIDENCE_MEMORY *p; char buffer[20]; p=p_thread_residence_memory_list; printf("|-------------------|--------------------|------------------|\n"); printf("| thread_name | start_address(kB) | size(KB) |\n"); printf("|-------------------|--------------------|------------------|\n"); while(p!=NULL){ printf("| %s",p->thread_name); print_space(18-strlen(p->thread_name)); printf("| %d",p->start_address); itoa( p->start_address, buffer, 10 ); print_space(19-strlen(buffer)); printf("| %d",p->size); itoa(p->size, buffer, 10 ); print_space(17-strlen(buffer)); printf("|\n"); p=p->next; }; printf("|-------------------|--------------------|------------------|\n\n"); } //最佳适应分配法:删除空闲区链表 void BF_delete_freearea_list(){ FREEAREA *temp; temp=p_free_area_list; while(temp!=NULL){ temp=p_free_area_list->next; free(p_free_area_list); p_free_area_list=temp; } p_free_area_list=NULL; } //最佳适应分配法:初始化内存申请链表 REQUIRE_MEMORY *BF_initialize_require_memory_list(REQUIRE_MEMORY *init_table,int num){ REQUIRE_MEMORY *temp; REQUIRE_MEMORY *head=NULL; REQUIRE_MEMORY *tail=NULL; int i; for(i=0;i<num;i++){ temp=(REQUIRE_MEMORY *)malloc(sizeof(REQUIRE_MEMORY)); strcpy(temp->thread_name,init_table[i].thread_name); temp->size=init_table[i].size; temp->duration=init_table[i].duration; temp->next=NULL; if(head==NULL) head=tail=temp; else{ tail->next=temp; tail=tail->next; } }; return head; } //最佳适应分配法:删除内存申请链表 void BF_delete_require_memory_list(){ REQUIRE_MEMORY *temp; temp=p_thread_require_memory_queue; while(temp!=NULL){ temp=p_thread_require_memory_queue->next; free(p_thread_require_memory_queue); p_thread_require_memory_queue=temp; } p_thread_require_memory_queue=NULL; } //最佳适应分配法:初始化线程驻留区链表 THREAD_RESIDENCE_MEMORY *BF_initialize_thread_residence_memory_list(THREAD_RESIDENCE_MEMORY *init_table,int num){ THREAD_RESIDENCE_MEMORY *temp; THREAD_RESIDENCE_MEMORY *head=NULL; THREAD_RESIDENCE_MEMORY *tail=NULL; int i; for(i=0;i<num;i++){ temp=(THREAD_RESIDENCE_MEMORY *)malloc(sizeof(THREAD_RESIDENCE_MEMORY)); strcpy(temp->thread_name,init_table[i].thread_name); temp->start_address=init_table[i].start_address; temp->size=init_table[i].size; temp->next=NULL; if(head==NULL) head=tail=temp; else{ tail->next=temp; tail=tail->next; } }; tail_thread_residence_memory_list=tail; return head; } //最佳适应分配法:删除线程驻留区链表 void BF_delete_thread_residence_memory_list(){ THREAD_RESIDENCE_MEMORY *temp=p_thread_residence_memory_list; temp=p_thread_residence_memory_list; while(temp!=NULL){ temp=p_thread_residence_memory_list->next; free(p_thread_residence_memory_list); p_thread_residence_memory_list=temp; } p_thread_residence_memory_list=NULL; } //最佳适应分配算法的线程:申请内存,驻留一段时间,释放内存 void BF_thread(void *data){ int start_address=-1; THREAD_RESIDENCE_MEMORY *temp; EnterCriticalSection(&CS_SCREEN); printf("create thread:%s\n",((REQUIRE_MEMORY *)(data))->thread_name); LeaveCriticalSection(&CS_SCREEN); //申请内存 while(1){ start_address=BF_require_memory(((REQUIRE_MEMORY *)(data))->size); if(start_address>=0) break; else Sleep(1000); } temp=(THREAD_RESIDENCE_MEMORY *)malloc(sizeof(THREAD_RESIDENCE_MEMORY)); strcpy(temp->thread_name,((REQUIRE_MEMORY *)(data))->thread_name); temp->start_address=start_address; temp->size=((REQUIRE_MEMORY *)(data))->size; temp->next=NULL; EnterCriticalSection(&CS_THREAD_MEMORY_LIST); //加入线程内存驻留区链表 tail_thread_residence_memory_list->next=temp; tail_thread_residence_memory_list=tail_thread_residence_memory_list->next; LeaveCriticalSection(&CS_THREAD_MEMORY_LIST); //显示线程内存驻留区链表 EnterCriticalSection(&CS_SCREEN); printf("after %s %s\n",((REQUIRE_MEMORY *)(data))->thread_name,"get memory:"); display_thread_residence_memory_list(); LeaveCriticalSection(&CS_SCREEN); Sleep(((REQUIRE_MEMORY *)(data))->duration); //释放内存 BF_release_memory(start_address,((REQUIRE_MEMORY *)(data))->size); } //最佳适应分配算法的内存申请函数 int BF_require_memory(int size){ //请读者自己实现这段代码 } //最佳适应分配算法的内存释放函数 void BF_release_memory(int start_address,int size){ //请读者自己实现这段代码 } //最佳分配算法的空闲区结点插入函数 void BF_insert_freearea(FREEAREA *free_node){ FREEAREA *p; FREEAREA *p_next; if(p_free_area_list==NULL) p_free_area_list=free_node; else{ p_next=p=p_free_area_list; while(p_next!=NULL&&p_next->size<free_node->size){ p=p_next; p_next=p_next->next; } if(p_next==NULL) //应插入到尾部 p->next=free_node; else if(p==p_next){ //应插入到头部 free_node->next=p; p_free_area_list=free_node; } else{ //应插入到p与p_next之间 free_node->next=p_next; p->next=free_node; } } } //最佳适应分配法:初始化空闲区链表 void BF_initialize_freearea_list(FREEAREA *init_table,int num){ FREEAREA *temp; int i; for(i=0;i<num;i++){ temp=(FREEAREA *)malloc(sizeof(FREEAREA)); temp->start_address=init_table[i].start_address; temp->size=init_table[i].size; temp->next=NULL; BF_insert_freearea(temp); } } //最佳分配算法的初始化程序 void BF( ) { int i=0; REQUIRE_MEMORY *p; HANDLE h_thread[MAX_THREAD]; InitializeCriticalSection(&CS_THREAD_MEMORY_LIST); InitializeCriticalSection(&CS_FREEAREA_LIST); InitializeCriticalSection(&CS_SCREEN); printf("最佳适应分配算法\n"); BF_initialize_freearea_list(init_free_area_table,5); p_thread_require_memory_queue=BF_initialize_require_memory_list(init_thread_require_memory_table,3); p_thread_residence_memory_list=BF_initialize_thread_residence_memory_list(init_thread_residence_memory_table,5); p=p_thread_require_memory_queue; while(p!=NULL){ h_thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(BF_thread),p,0,NULL); i++; p=p->next; }; //等待所有线程结束 WaitForMultipleObjects(MAX_THREAD,h_thread,TRUE,-1); //显示驻留线程链表 EnterCriticalSection(&CS_SCREEN); printf("after all threads have finished:\n"); display_thread_residence_memory_list(); LeaveCriticalSection(&CS_SCREEN); //删除各种链表 BF_delete_freearea_list(); BF_delete_require_memory_list(); BF_delete_thread_residence_memory_list(); getch(); printf("\n"); } void main( ){ BF( ); }根据上面的要求和部分代码,补充上面代码实现动态异长分区内存分配与去配算法的设计-最佳适应算法
最新发布
05-28
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值