CS107 Assignment 3: vector and hashset
任务地址:https://see.stanford.edu/materials/icsppcs107/11-Assignment-3-Vector.pdf
任务1:The C vector
用c制作类似于c++的vector
一些区别:
1. c 没有 public 和 private 之分,所以不让用户见的函数在头文件cpp中用 static 修饰
2. c 没有方法,因此所有的函数的输入参数中都要加入 v,即没有 this->
3. c 用struct代替类的私有变量
一些注意事项:
1. 多用 assert( ) 确保用户的输入参数是正确的
2. memcpy( )不能用于有重叠部分的复制,此时用memmove( )替代
3. malloc( )和realloc( )里面参数要注意乘size
vector结构体:
typedef struct {
void* elems;
int elemSize;
int initialAllocation;
int logLength;
int allocLength;
VectorFreeFunction freeFn;
} vector;
vector.c:
#include "vector.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <search.h>
void VectorNew(vector *v, int elemSize, VectorFreeFunction freeFn, int initialAllocation)
{
assert(elemSize > 0);
v->elemSize = elemSize;
assert(initialAllocation >0);
v->allocLength = initialAllocation;
v->initialAllocation = initialAllocation;
v->logLength = 0;
v->freeFn = freeFn;
v->elems = malloc(v->allocLength *elemSize);
assert(v->elems != NULL);
}
void VectorDispose(vector *v)
{
if(v->freeFn != NULL)
{
for(int i=0; i< v->logLength; i++)
v->freeFn(VectorNth(v,i));
}
free(v->elems);
}
int VectorLength(const vector *v)
{
return v->logLength;
}
static void *VectorRawNth(const vector *v, int position)
{
return (char *) v->elems + (position * v->elemSize);
}
void *VectorNth(const vector *v, int position)
{
assert(position >= 0);
assert(position < v->logLength);
return (char*)v->elems + (v->elemSize * position);
}
void VectorReplace(vector *v, const void *elemAddr, int position)
{
assert(position >= 0);
assert(position < v->logLength);
//先清理
if (v->freeFn != NULL)
v->freeFn(VectorNth(v, position));
void* destAddr;
destAddr = VectorNth(v,position);
memcpy(destAddr, elemAddr, v->elemSize);
}
static void VectorElemShift(vector *v, int position, int delta)
{
void *src = VectorRawNth(v, position);
void *dest = VectorRawNth(v, position + delta);
size_t len = (char *) VectorRawNth(v, v->logLength) - (char *) src;
memmove(dest, src, len);
}
static void VectorGrow(vector *v)
{
v->allocLength += v->initialAllocation;
v->elems = realloc(v->elems, v->allocLength * v->elemSize);
assert(v->elems != NULL);
}
void VectorInsert(vector *v, const void *elemAddr, int position)
{
assert(position >= 0);
assert(position <= v->logLength);
if(v->logLength == v->allocLength)
VectorGrow(v);
VectorElemShift(v, position, 1);
memcpy(VectorRawNth(v, position), elemAddr, v->elemSize);
v->logLength++;
}
void VectorAppend(vector *v, const void *elemAddr)
{
if(v->logLength == v->allocLength)
VectorGrow(v);
memcpy(VectorRawNth(v, v->logLength), elemAddr, v->elemSize);
v->logLength++;
}
void VectorDelete(vector *v, int position)
{
assert(position >= 0);
assert(position < v->logLength);
if (v->freeFn != NULL)
v->freeFn(VectorNth(v, position));
VectorElemShift(v, position+1, -1);
v->logLength--;
}
void VectorSort(vector *v, VectorCompareFunction compare)
{
assert(compare != NULL);
qsort(v->elems, v->logLength, v->elemSize, compare);
}
void VectorMap(vector *v, VectorMapFunction mapFn, void *auxData)
{
assert(mapFn != NULL);
for (int i = 0; i < v->logLength; i++)
mapFn(VectorNth(v, i), auxData);
}
static const int kNotFound = -1;
int VectorSearch(const vector *v, const void *key, VectorCompareFunction searchFn, int startIndex, bool isSorted)
{
assert(key != NULL);
assert(searchFn != NULL);
assert(startIndex >= 0);
assert(startIndex <= v->logLength);
void *found;
void *base = VectorRawNth(v, startIndex);
size_t numElems = v->logLength - startIndex;
if (isSorted)
found = bsearch(key, base, numElems, v->elemSize, searchFn);
else
found = lfind(key, base, &numElems, v->elemSize, searchFn); //num是指针接受传递
if(found != NULL)
return (int)( (char*)found - (char*)v )/v->elemSize;
else
return kNotFound;
}
结果展示:
------------------------- Starting the basic test...
First, here is the alphabet: ABCDEFGHIJKLMNOPQRSTUVWXYZ
After append digits: ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
After sorting: 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ
Found 'J' in sorted array? Yes. How about unsorted? Yes.
Found '$' in sorted array? No. How about unsorted? No.
After lowercase every other letter: 0123456789aBcDeFgHiJkLmNoPqRsTuVwXyZ
After insert dashes: 012-345-678-9aB-cDe-FgH-iJk-LmN-oPq-RsT-uVw-XyZ
After deleting dashes: 0123456789aBcDeFgHiJkLmNoPqRsTuVwXyZ
After adding and deleting to very end: 0123456789aBcDeFgHiJkLmNoPqRsTuVwXyZ
After changing all s to *: 0123456789aBcDeFgHiJkLmNoPqR*TuVwXyZ
------------------------- Starting the more advanced tests...
Generating all of the numbers between 0 and 3021376 (using some number theory). [All done]
Sorting all of those numbers. [Done]
Confirming everything was properly sorted. [Yep, it's sorted]
Erasing everything in the vector by repeatedly deleting the 100th-to-last remaining element (be patient).
[Okay, almost done... deleting the last 100 elements... and we're all done... whew!]
------------------------- Starting the memory tests...
Creating a vector designed to store dynamically allocated C-strings.
Populating the char * vector with the question words.
Mapping over the char * vector (ask yourself: why are char **'s passed to PrintString?!!)
why
how
where
what
who
Finally, destroying the char * vector.
任务2: The C hashset
用刚刚制作的vector制作hashset
所谓hashset,就是把数存到hash桶里,所以事先设定桶的个数,还有hash函数(判断把数放哪个桶里)
使用hashset,可以减少查找的时间,先判断在哪个桶里,再直接在桶里找
hashset结构体:
typedef struct
{
int elemSize;
int numBuckets;
vector* buckets;
HashSetHashFunction hashfn;
HashSetCompareFunction comparefn;
HashSetFreeFunction freefn;
} hashset;
hashset.cpp:
#include "hashset.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
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->elemSize = elemSize;
h->numBuckets = numBuckets;
h->hashfn = hashfn;
h->comparefn = comparefn;
h->freefn = freefn;
h->buckets = (vector*)malloc(sizeof(vector) * numBuckets);
for (int i = 0; i < numBuckets; i++) {
VectorNew(h->buckets + i, elemSize, freefn, 10);
}
}
void HashSetDispose(hashset *h)
{
if (h->freefn != NULL)
{
for (int i = 0; i < h->numBuckets; i++)
VectorDispose(h->buckets + i);
}
free(h->buckets);
}
int HashSetCount(const hashset *h)
{
int count = 0;
for (int i = 0; i < h->numBuckets; i++)
count += VectorLength(h->buckets + i);
return count;
}
void HashSetMap(hashset *h, HashSetMapFunction mapfn, void *auxData)
{
assert(mapfn != NULL);
for (int i = 0; i < h->numBuckets; i++)
VectorMap(h->buckets + i, mapfn, auxData);
}
void HashSetEnter(hashset *h, const void *elemAddr)
{
void *existing = HashSetLookup(h, elemAddr);
if (existing == NULL)
{
int bucket = h->hashfn(elemAddr, h->numBuckets);
assert(bucket >= 0);
assert(bucket < h->numBuckets);
vector *v = h->buckets + bucket;
VectorAppend(v, elemAddr);
VectorSort(v, h->comparefn);
}
//想不到把,就算找到了也要加进去
else
memcpy(existing, 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(bucket < h->numBuckets);
vector *v = h->buckets + bucket;
int pos = VectorSearch(v, elemAddr, h->comparefn, 0, true);
return pos == -1 ? NULL : VectorNth(v, pos);
}
结果展示:
------------------------- Starting the HashTable test
Here is the unordered contents of the table:
Character h occurred 164 times
Character i occurred 185 times
Character k occurred 15 times
Character l occurred 122 times
Character m occurred 67 times
Character n occurred 263 times
Character o occurred 240 times
Character p occurred 82 times
Character q occurred 64 times
Character r occurred 319 times
Character s occurred 289 times
Character t occurred 406 times
Character u occurred 206 times
Character v occurred 35 times
Character w occurred 15 times
Character x occurred 1 times
Character y occurred 68 times
Character z occurred 3 times
Character a occurred 214 times
Character b occurred 44 times
Character c occurred 279 times
Character d occurred 111 times
Character e occurred 500 times
Character f occurred 146 times
Character g occurred 13 times
Here are the trials sorted by char:
Character a occurred 214 times
Character b occurred 44 times
Character c occurred 279 times
Character d occurred 111 times
Character e occurred 500 times
Character f occurred 146 times
Character g occurred 13 times
Character h occurred 164 times
Character i occurred 185 times
Character k occurred 15 times
Character l occurred 122 times
Character m occurred 67 times
Character n occurred 263 times
Character o occurred 240 times
Character p occurred 82 times
Character q occurred 64 times
Character r occurred 319 times
Character s occurred 289 times
Character t occurred 406 times
Character u occurred 206 times
Character v occurred 35 times
Character w occurred 15 times
Character x occurred 1 times
Character y occurred 68 times
Character z occurred 3 times
Here are the trials sorted by occurrence & char:
Character e occurred 500 times
Character t occurred 406 times
Character r occurred 319 times
Character s occurred 289 times
Character c occurred 279 times
Character n occurred 263 times
Character o occurred 240 times
Character a occurred 214 times
Character u occurred 206 times
Character i occurred 185 times
Character h occurred 164 times
Character f occurred 146 times
Character l occurred 122 times
Character d occurred 111 times
Character p occurred 82 times
Character y occurred 68 times
Character m occurred 67 times
Character q occurred 64 times
Character b occurred 44 times
Character v occurred 35 times
Character k occurred 15 times
Character w occurred 15 times
Character g occurred 13 times
Character z occurred 3 times
Character x occurred 1 times