您的位置:首页 > 编程语言 > C语言/C++

单向链表及其应用(C语言)

2012-12-16 16:20 260 查看

一、单向链表

//list.h
#ifndef LIST_H_
#define LIST_H_
#include <stdlib.h>

typedef struct ListElement_ {
	void *data;
	struct ListElement_ *next;
} ListElement;

typedef struct List_ {
	int size;
	int (*match) (const void *data1, const void *data2);
	void (*destory) (void* data);
	ListElement *head;
	ListElement *tail;
} List;

void list_init(List *list, void (*destory) (void *data));  //初始化链表,每次使用前都要去初始化
void list_destory(List *list);				  //销毁链表
int list_ins_next(List *list, ListElement *element, const void *data);  //在指定的元素画面插入一个元素,如果element为NULL,则在表头插入
int list_rem_next(List *list, ListElement *element, void *data);       //移除指定元素的后面一个元素
#define list_size(list) ((list)->size)
#define list_head(list) ((list)->head)
#define list_tail(list)	((list)->tail)
#define list_is_head(list, element) ((element) == (list->head) ? 1 : 0)
#define list_is_tail(element)		((element)->next == NULL ? 1 : 0)
#define list_data(element)			((element)->data)
#define list_next(element)			((element)->next)

#endif
实现文件list.c

#include "list.h"
#include 
#include 
#include 
void list_init(List *list, void (*destory)(void *data)) {
	if (list == NULL) return;
	list->size = 0;
	list->match = NULL;
	list->destory = destory;
	list->head = NULL;
	list->tail = NULL;
}

void list_destory(List *list) {
	if (list == NULL) return;
	void *data;
	while (list_size(list) > 0) {
		if (list_rem_next(list, NULL, (void **)&data) == 0 && list->destory != NULL) {
			list->destory(data);
		}	
	}
	memset(list, 0, sizeof(list));
}

int list_ins_next(List *list, ListElement *elem, const void *data) {
	if (!list) return -1;
	ListElement *ins_elem = (ListElement*)malloc(sizeof(ListElement));
	list_data(ins_elem) = data;
	list_next(ins_elem) = NULL;
	if (!elem) {
		if (list_size(list) == 0)  list_tail(list) = ins_elem;
		list_next(ins_elem) = list_head(list);
		list_head(list) = ins_elem;
	} else {
		if (list_next(elem) == NULL) list_tail(list) = ins_elem;
		list_next(ins_elem) = list_next(elem);
		list_next(elem) = ins_elem;
	}
	list->size++;
	return 0;
}

int list_rem_next(List *list, ListElement *elem, void **data) {
	if (!list || list_size(list) == 0) return -1;
	ListElement *old_element;
	if (!elem) {
		*data = list_data(list_head(list));
		old_element = list_head(list);
		list_head(list) = list_next(list_head(list)); 
		
		if (list_size(list) == 1) list->tail = NULL;
	} else {
		if (elem->next == NULL) return -1;
		*data = list_data(list_next(elem));
		old_element = (list_next(elem));
		list_next(elem) = list_next(list_next(elem));
		
		if (elem->next == NULL) list->tail = elem;
	}
	free(old_element);
	list_size(list)--;
	return 0;
}

二、单向链表的应用

单向链表可以应用于操作系统的虚拟内存中,我们知道程序使用的内存空间大于实际的物理内存。虚拟内存是一种地址空间的映射机制,它允许进程不必完全加载到物理内存中也可以得到运行。这种方式的优点:

进程可以使用比系统实际所允许的物理内存大得多的地址空间。
多个进程能够共享系统的内存以并发的方式执行。

可以使用页表来实现虚拟内存的机制。每个进程都有它自己的页表,将它的虚拟地址空间中的页映射到物理内存中的页帧上。当某个进程引用一个虚拟地址时,页表中的某项需要检查并决定该页关联到哪个物理页帧上。



模拟内存页表的代码:
#include "list.h"
//从空闲的页帧链表中获取空闲页帧号
int alloc_frame(List *list) {
	if (list_size(list) == 0) return -1;
	int *frame_number;
	if (list_size(list)) {
		list_rem_next(list, NULL, (void**)&frame_number);
	}
	return *frame_number;
}

//接受一个页帧号并将其放回空闲页帧链表中
int free_frame(List *list, int frame_number) {
	int *data;
	
	if ((data = (int*)malloc(sizeof(int))) == NULL) return -1;
	
	*data = frame_number;
	
	if (list_ins_next(list, NULL, data))
		return -1;
	return 0;
}

void init_page(List *list) {
	int i;
	for (i = 0; i < 10; ++i) {
		int *j = (int*) malloc(sizeof(int));
		*j = rand() % 50;
		list_ins_next(list, NULL, j);
	}
}

void print(List *list) {
	int i = 0;
	ListElement *elem = list->head;
	printf("list size is : %d\n", list_size(list));
	for (; i < list_size(list) && elem != NULL ; ++i) {
		printf("%d\n", *(int*)elem->data);
		elem = elem->next;
	}
}

int real_mem[50] = {0,}; //模拟系统中真实的内存
	
int get_mem(int frame) {  //获取真实的内存值
	return real_mem[frame];
}
	
int main() {
	List *list = (List*)malloc(sizeof(*list));
	list_init(list, free);
	init_page(list);  //初始化一个页表
	print(list);
	int frame = alloc_frame(list);
	//取得了页帧号,获取真实的物理内存
	int use_mem = get_mem(frame);
	//TODO: 使用这块内存
	list_destory(list);
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: