Stanford CS107 Assignment 3: vector and hashset

在这里插入图片描述

Abstract

本人正在学习Stanford CS107。这门课很不错,我简单把这门课的信息说一下。

keyvalue
官网https://see.stanford.edu/Course/CS107
课程名编程范式
所需基础C,C++,数据结构与算法
上课视频Bilibili搜索 https://www.bilibili.com/video/av9789206 (可能会失效)
我做的作业https://github.com/peanwang/stanford-cs107

Assignment Task

这次的作业也分为了两个部分。主要会使用下面几个函数:
内存管理

malloc
realloc
free
memcpy
memmove

功能性函数

qsort
lsearch
bsearch

Task I: The C vector

第一个任务是实现C vector。其算法和C++的vector使用的是一样的,都是均摊


在handout里老师给出了为什么选择C vector,而不是C++的vector
①C++ 的vector会占用大量内存。对于嵌入式系统来说,C vector就比C++ vector适合。(C++ vector每有一种数据类型,都要一份代码副本,会导致代码膨胀)
②C vector会比C++ vector快


这次的任务就是实现vector。声明vector结构体和实现下面的函数。并通过老师写的测试程序。

typedef int (*VectorCompareFunction)(const void *elemAddr1,const void *elemAddr2); 
typedef void (*VectorMapFunction)(void *elemAddr, void *auxData); 
typedef void (*VectorFreeFunction)(void *elemAddr); 
typedef struct {// implementation specific... you decide this } vector; 
void  VectorNew(vector *v, int elemSize,VectorFreeFunction freefn, int initialAllocation); 
void  VectorDispose(vector *v); int   VectorLength(const vector *v); 
void *VectorNth(const vector *v, int position);
void  VectorInsert(vector *v, const void *elemAddr, int position); 
void  VectorAppend(vector *v, const void *elemAddr); 
void  VectorReplace(vector *v, const void *elemAddr, int position);
void  VectorDelete(vector *v, int position); 
int   VectorSearch(const vector *v, const void *key,VectorCompareFunction searchfn, int startIndex,bool isSorted); 
void  VectorSort(vector *v, VectorCompareFunction comparefn); 
void  VectorMap(vector *v, VectorMapFunction mapfn, void *auxData); 

Task I: The C hashset

使用Task Ⅰ中C vector,声明hashset的结构体和实现下面的函数。
而且handout里有说要充分利用vector的函数。因为
①会让工作很有趣
②not re-invent the wheel.不要重复造轮子

typedef int (*HashSetHashFunction)(const void *elemAddr, int numBuckets);
typedef int (*HashSetCompareFunction)(const void *elemAddr1,
 const void *elemAddr);
typedef void (*HashSetMapFunction)(void *elemAddr, void *auxData);
typedef void (*HashSetFreeFunction)(void *elemAddr);
typedef struct {
// implementation specific… you decide this as well
} hashset;
void HashSetNew(hashset *h, int elemSize, int numBuckets,
 HashSetHashFunction hashfn, HashSetCompareFunction comparefn,
 HashSetFreeFunction freefn);
void HashSetDispose(hashset *h);
int HashSetCount(const hashset *h);
void HashSetEnter(hashset *h, const void *elemAddr);
void *HashSetLookup(const hashset *h, const void *elemAddr);
void HashSetMap(hashset *h, HashSetMapFunction mapfn, void *auxData);

Assignment solution

Task I: The C vector

说实话:和老师上课讲的stack很像,照着模仿就行了。
我说下lsearch。我还以为lsearch和老师上课讲的是一样的。但是 man lsearch,发现有一些差别。
首先:lsearch和lfind都在search.h里,其函数签名如下:

       void *lfind(const void *key, const void *base, size_t *nmemb,
                size_t size, int(*compar)(const void *, const void *));

       void *lsearch(const void *key, void *base, size_t *nmemb,
                size_t size, int(*compar)(const void *, const void *));

其第三个参数居然是个指针。o_o …
lsearch和lfind都是线性搜索,但是
lfind如果成功找到,返回其指针。失败返回NULL。
lsearch如果成功找到,返回其指针。如果失败,会将查找的元素添加到数组末尾,并返回其指针。
很显然:我们需要的是lfind,而不是lsearch,老师的FAQ也提到了这个


vector结构体

typedef struct {
	void* elems;
	int elemsize;
	int logicallen;
	int alloclen;
	VectorFreeFunction freefn;
} vector;

函数实现

static void VectorGrow(vector *v){
	v->alloclen *= 2;
	v->elems = realloc(v->elems, v->alloclen*v->elemsize);
}

void VectorNew(vector *v, int elemSize, VectorFreeFunction freeFn, int initialAllocation){
	assert( elemSize>0);
	assert( initialAllocation>=0);
	if( initialAllocation==0)
		initialAllocation = 4;
	v->elemsize = elemSize;
	v->logicallen = 0;
	v->alloclen = initialAllocation;
	v->elems = malloc( elemSize*v->alloclen);
	assert(v->elems != NULL);
	v->freefn = freeFn;
}

void VectorDispose(vector *v){
	if(v->freefn !=NULL){
		for(int i=0;i<v->logicallen;i++)
			v->freefn((char*)v->elems+i*v->elemsize);
	}
	free(v->elems);
}

int VectorLength(const vector *v){ 
	return v->logicallen; 
}

void *VectorNth(const vector *v, int position){
	assert(position>=0);
	assert(v->logicallen>position);
	return (char*)v->elems+position*v->elemsize;
}

void VectorReplace(vector *v, const void *elemAddr, int position){
	assert(position>=0);		
	assert(v->logicallen>position);
	char* replace = VectorNth(v,position);	
	memcpy(replace, elemAddr, v->elemsize);
}

void VectorInsert(vector *v, const void *elemAddr, int position){
	assert(position>=0);                
	assert(v->logicallen>=position);
	if ( v->logicallen == v->alloclen)
		VectorGrow(v);
	if (v->logicallen == position)
		VectorAppend(v, elemAddr);
	else{
		char *front = VectorNth(v, position);
		char* end = front + v->elemsize;
		int movesize =  v->elemsize*(v->logicallen-position);
		char* buffer = (char*)malloc(movesize);	
		memcpy(buffer, front, movesize);
		memcpy(front, elemAddr, v->elemsize);	
		memcpy(end, buffer, movesize);
		free(buffer);
		v->logicallen++;
	}
}

void VectorAppend(vector *v, const void *elemAddr)
{
	if ( v->logicallen == v->alloclen)
		VectorGrow(v);
	v->logicallen++;
	void *target = VectorNth(v,v->logicallen-1);
	memcpy(target, elemAddr, v->elemsize);
}

void VectorDelete(vector *v, int position){
	assert(position>=0);
	assert(v->logicallen>position);
	char *target = VectorNth(v,position);
	if(v->freefn !=NULL){
		v->freefn(target);
	}
	if(v->logicallen-1 != position){   //the last one 
		int end_size = v->logicallen-position-1;
		for(int i=0;i<end_size;i++){
			char* next = target + v->elemsize;			
			memcpy(target, next, v->elemsize);
			target = next;
		}
	}
	v->logicallen--;
}

void VectorSort(vector *v, VectorCompareFunction compare){
	assert(compare != NULL);
	qsort(v->elems, v->logicallen, v->elemsize, compare);
}

void VectorMap(vector *v, VectorMapFunction mapFn, void *auxData){
	assert(mapFn != NULL);
	for(int i=0;i<v->logicallen;i++){
		char *target = (char*)v->elems + i*v->elemsize;		
		mapFn(target, auxData);
	}
}


static const int kNotFound = -1;
int VectorSearch(const vector *v, const void *key, VectorCompareFunction searchFn, int startIndex, bool isSorted){
	assert(startIndex>=0);
	assert(v->logicallen>=startIndex);
	assert(key != NULL);
	assert(searchFn != NULL);
	char* result;
	char* base = (char*)v->elems + startIndex*v->elemsize;
	if(isSorted)
		result = bsearch(key, base, v->logicallen-startIndex, v->elemsize, searchFn);
	else{
		size_t size = v->logicallen-startIndex;
		result = lfind(key, base, &size, v->elemsize, searchFn);
	}
	return result==NULL ?kNotFound :(result-(char*)v->elems)/v->elemsize;
} 

完成测试

在这里插入图片描述

Task II: The C hashset

使用Task ①中实现的vector,会使hashset的实现变得很轻松。基本上没有遇到什么问题,一遍就过了。


hashset结构体

typedef struct {
	vector* bucket;
	int elemsize;
	int elemNum;
	int numBuckets;
	HashSetHashFunction hashfn;
	HashSetCompareFunction comparefn;
	HashSetFreeFunction freefn;
} hashset;

函数实现:

void HashSetNew(hashset *h, int elemSize, int numBuckets,HashSetHashFunction hashfn, HashSetCompareFunction comparefn, HashSetFreeFunction freefn){
	assert(elemSize>0);
	assert(numBuckets>0);
	assert(hashfn !=NULL);
	assert(comparefn !=NULL);
	h->elemNum = 0;
	h->elemsize = elemSize;
	h->numBuckets = numBuckets;
	h->hashfn= hashfn;
	h->comparefn = comparefn;
	h->freefn = freefn;
	h->bucket = (vector*)malloc(sizeof(vector)*h->numBuckets);
	assert(h->bucket);
	for(int i=0;i<numBuckets;i++)
		VectorNew(h->bucket+i,elemSize,freefn,4);
}


void HashSetDispose(hashset *h){
	if(h->freefn !=NULL){
		for(int i=0;i<h->numBuckets;i++)	
			VectorMap(h->bucket+i, h->freefn, NULL);
	}
	for(int i=0;i<h->numBuckets;i++)	
		VectorDispose(h->bucket+i);	
	free(h->bucket);
}

int HashSetCount(const hashset *h){ 
	return h->elemNum;
}

void HashSetMap(hashset *h, HashSetMapFunction mapfn, void *auxData){
	assert(mapfn !=NULL);
	for(int i=0;i<h->numBuckets;i++){
		VectorMap(h->bucket+i, mapfn, auxData);
	}
}


void HashSetEnter(hashset *h, const void *elemAddr){
	assert(elemAddr !=NULL);
	void* result = HashSetLookup(h, elemAddr);
	if(result == NULL){
		int bucket = h->hashfn(elemAddr, h->numBuckets);	
		assert(bucket>=0);
		assert(h->numBuckets>bucket);
		VectorAppend(h->bucket+bucket, elemAddr);	
		h->elemNum++;	
	}
	else{
		memcpy(result, elemAddr, h->elemsize);
	}
}


void *HashSetLookup(const hashset *h, const void *elemAddr){ 
	assert(elemAddr !=NULL);	
	int bucket = h->hashfn(elemAddr, h->numBuckets);	
	assert(bucket>=0);
	assert(h->numBuckets>bucket);	
	int result = VectorSearch(h->bucket+bucket, elemAddr, h->comparefn, 0, false);
	return result==-1? NULL: VectorNth(h->bucket+bucket, result);
}

完成测试

在这里插入图片描述

Assignment think

不知道是不是经过上次作业的折磨,这次作业写的非常快,两天就写完了,爽q(≧▽≦q)。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值