C K&;R第6-6节表格查找:哈希值相同时覆盖

C K&;R第6-6节表格查找:哈希值相同时覆盖,c,hash,C,Hash,我很难理解这一点 首先,我想指出,当我从输入命令行声明这一点时: #define Please 100 #define routine 120 因为“请”和“例程”都有相同的散列值。我的程序覆盖了hashtab值,从我的输入控制台键入'Please'的值为120。如何解决覆盖问题,或者它只是本书的一部分 其次,这一部分 struct nlist *lookup (char *s) { struct nlist *np; for (np = hashtab[hash(s)]; np != NUL

我很难理解这一点

首先,我想指出,当我从输入命令行声明这一点时:

#define Please 100
#define routine 120
因为“请”和“例程”都有相同的散列值。我的程序覆盖了hashtab值,从我的输入控制台键入'Please'的值为120。如何解决覆盖问题,或者它只是本书的一部分

其次,这一部分

struct nlist *lookup (char *s)
{
struct nlist *np;
for (np = hashtab[hash(s)]; np != NULL; np = np->next)
    return np;
return NULL;
}
特别是在for循环语句中。我的问题是for循环如何可以重复多次?因为我看到的只是每个hashtab[hash(s)]值的一个实例

这是完整的代码。您可以使用gcc来运行它。Undef()工作正常

#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
//#include <vld.h>
#define MAXWORD 100

struct nlist {
    struct nlist *next;
    char *name;
    char *defn;
};

void error(int, char *);
int getca(void); // getch()
void getdef(void);
int getword(char *, int);
struct nlist *install(char *, char *);
struct nlist *lookup(char *);
void skipblanks(void);
void undef(char *);
void ungetca(int); // ungetch()
void ungets(const char *);

#define HASHSIZE 101
unsigned hash(char *);
static struct nlist *hashtab[HASHSIZE];
char *strdupli (char *); //strdup() function

int main(void)
{
char w[MAXWORD];
struct nlist *p;

while (getword(w, MAXWORD) != EOF)
    if (strcmp(w, "#") == 0) /* beginning of direct */
        getdef();
    else if (!isalpha(w[0]))
        printf("%s", w);    /* cannot be defined */
    else if ((p = lookup(w)) == NULL)
        printf("%s", w);   /* not defined */
    else
        ungets(p->defn); /* push definition */
return 0;
}

void ungets(const char *s)
{
size_t i = strlen(s);
while(i > 0)
    ungetca(s[--i]);
}

void getdef(void)
{
    int i;
    char def[MAXWORD], dir[MAXWORD], name[MAXWORD];
skipblanks();
if (!isalpha(getword(dir, MAXWORD)))
    error (dir[0],
    "getdef: expecting a directive after #");
else if (strcmp(dir, "define") == 0) {
    skipblanks();
    if (!isalpha(getword(name, MAXWORD)))
        error(name[0],
        "getdef: non-alpha - name expected");
    else {
        skipblanks();
        for(i = 0; i < MAXWORD - 1; i++)
            if((def[i] = getca()) == EOF ||
                                    def[i] == '\n')
                break;  /*end of definition*/
        def[i] = '\0';
        if(i <= 0)      /* no definition */
            error('\n', "getdef: incomplete define");
        else            /* install definition */
            install (name, def);
    }
} else if (strcmp(dir, "undef") == 0) {
    skipblanks();
    if(!isalpha(getword(name, MAXWORD)))
        error(name[0], "getdef: non-alpha in undef");
    else
        undef(name);
} else
    error(dir[0],
    "getdef: expecting a directive after #");
}



struct nlist *install(char *name, char *defn)
{
struct nlist *np;
unsigned hashval;
if ((np = lookup(name)) == NULL) { /* not found */
    np = (struct nlist *) malloc(sizeof(*np));
    if (np == NULL || (np->name = strdupli(name)) == NULL)
        return NULL;
    hashval = hash(name);
    np->next = hashtab[hashval];
    hashtab[hashval] = np;
} else {/* already there */
    free((void *) np->defn); /*free previous defn */
}
if ((np->defn = strdupli(defn)) == NULL)
    return NULL;
return np;
 }

void undef(char *s)
{
int h;
struct nlist *prev, *np;

prev = NULL;
h = hash(s);
for(np = hashtab[h]; np != NULL; np = np->next) {
    if(strcmp(s, np->name)==0)
        break;
    prev = np;
}
if (np != NULL) {
    if (prev == NULL)
        hashtab[h] = np->next;
    else
        prev->next = np->next;
    free((void *) np->name);
    free((void *) np->defn);
    free((void *) np);
}
}

unsigned hash(char *s)
{
unsigned hashval;
for (hashval = 0; *s != '\0'; s++)
    hashval = *s + 31 * hashval;
return hashval % HASHSIZE;
}

struct nlist *lookup (char *s)
{
struct nlist *np;
for (np = hashtab[hash(s)]; np != NULL; np = np->next)
    return np;
return NULL;
}

int getword(char *word, int lim)
{
    int c, getca(void);
    void ungetca(int);
    char *w = word;

    while(isspace(c = getca()))
        ;
    if(c != EOF)
        *w++ = c;
    if(!isalpha(c)) {
        *w = '\0';
    return c;
}
    for( ; --lim > 0; w++)
        if(!isalnum(*w = getca())) {
            ungetca(*w);
            break;
        }
    *w = '\0';
    return word[0];
}

void error(int c, char *s)
{
    printf("error: %s\n", s);
        while(c != EOF && c != '\n')
    c = getca();
}

void skipblanks (void)
{
    int c;
while ((c = getca()) == ' ' || c == '\t')
;
ungetca(c);
}

void strcopy (char *, const char *);
char *strdupli (char *s) /* make a duplicate of s */
{
    char *p;
    p = (char *) malloc (strlen(s) + 1);
    if (p != NULL)
        strcopy(p, s);
    return p;
}

void strcopy (char *s, const char *t)
{
        while ((*s++ = *t++) != '\0')
        ;
}

#define BUFSIZE 100
char buf[BUFSIZE]; /* buffer for ungetch */
int bufp = 0; /* next free position in buf */
int getca(void) /* get a (possibly pushed-back) character */
{
    return (bufp > 0) ? buf[--bufp] : getchar();
}

void ungetca(int c) /* push character back on input */
{
    if (bufp >= BUFSIZE)
       printf("ungetch: too many characters\n");
    else
    buf[bufp++] = c;
}
#包括
#包括
#包括
#包括
//#包括
#定义MAXWORD 100
结构列表{
结构nlist*next;
字符*名称;
char*defn;
};
无效错误(int,char*);
int getca(void);//getch()
void getdef(void);
int getword(char*,int);
结构nlist*安装(字符*,字符*);
结构nlist*查找(char*);
空心板(空心板);
无效未定义(字符*);
无效ungetca(int);//取消蚀刻()
无效unget(常量字符*);
#定义HASHSIZE 101
无符号散列(char*);
静态结构nlist*hashtab[HASHSIZE];
char*strdupli(char*)//strdup()函数
内部主(空)
{
字符w[MAXWORD];
结构列表*p;
while(getword(w,MAXWORD)!=EOF)
如果(strcmp(w,“#”)==0)/*直接*/
getdef();
else如果(!isalpha(w[0]))
无法定义printf(“%s”,w);/**/
else如果((p=lookup(w))==NULL)
printf(“%s”,w);/*未定义*/
其他的
ungets(p->defn);/*推送定义*/
返回0;
}
无效unget(常量字符*s)
{
尺寸=标准长度;
而(i>0)
ungetca(s[--i]);
}
void getdef(void)
{
int i;
char def[MAXWORD],dir[MAXWORD],name[MAXWORD];
skipblanks();
if(!isalpha(getword(dir,MAXWORD)))
错误(目录[0],
“getdef:在#”之后应为指令”;
else if(strcmp(dir,“define”)==0){
skipblanks();
如果(!isalpha(getword(name,MAXWORD)))
错误(名称[0],
“getdef:应为非alpha名称”);
否则{
skipblanks();
对于(i=0;inext=hashtab[hashval];
hashtab[hashval]=np;
}否则{/*已经在那里了*/
自由((void*)np->defn);/*自由先前的defn*/
}
如果((np->defn=strdupli(defn))==NULL)
返回NULL;
返回np;
}
无效未定义(字符*s)
{
int-h;
结构nlist*prev,*np;
prev=NULL;
h=散列;
for(np=hashtab[h];np!=NULL;np=np->next){
如果(strcmp(s,np->name)==0)
打破
prev=np;
}
如果(np!=NULL){
if(prev==NULL)
hashtab[h]=np->next;
其他的
上一个->下一个=np->下一个;
自由((void*)np->name);
自由((空*)np->defn);
自由((空*)np);
}
}
无符号散列(字符*s)
{
无符号hashval;
对于(hashval=0;*s!='\0';s++)
hashval=*s+31*hashval;
返回hashval%HASHSIZE;
}
结构nlist*查找(字符*s)
{
结构列表*np;
for(np=hashtab[hash(s)];np!=NULL;np=np->next)
返回np;
返回NULL;
}
int getword(字符*word,int lim)
{
int c,getca(无效);
无效ungetca(int);
char*w=单词;
while(isspace(c=getca())
;
如果(c!=EOF)
*w++=c;
如果(!isalpha(c)){
*w='\0';
返回c;
}
对于(;--lim>0;w++)
如果(!isalnum(*w=getca()){
ungetca(*w);
打破
}
*w='\0';
返回字[0];
}
无效错误(int c,char*s)
{
printf(“错误:%s\n”,s);
而(c!=EOF&&c!='\n')
c=getca();
}
空心板(空心板)
{
INTC;
而((c=getca())=''|| c=='\t')
;
ungetca(c);
}
无效结构副本(字符*,常量字符*);
char*strdupli(char*s)/*复制s*/
{
char*p;
p=(char*)malloc(strlen+1);
如果(p!=NULL)
strcopy(p,s);
返回p;
}
无效strcopy(字符*s,常量字符*t)
{
而((*s++=*t++)!='\0')
;
}
#定义BUFSIZE 100
char buf[BUFSIZE];/*用于取消蚀刻的缓冲区*/
int bufp=0;/*buf中的下一个自由位置*/
int getca(void)/*获取一个(可能向后推)字符*/
{
返回(bufp>0)?buf[--bufp]:getchar();
}
void ungetca(int c)/*在输入时将字符推回*/
{
如果(bufp>=BUFSIZE)
printf(“取消蚀刻:字符太多\n”);
其他的
buf[bufp++]=c;
}

这里有一个例子,假设其他一切都与K&R的例子相同:

定义打印哈希表的函数:

void printTable(struct nlist* ptable[])
{
    for (int i=0; i<HASHSIZE; i++)
        if (ptable[i] != NULL)
        {
            printf("Hash table index %d content: \n", i);
            int j = 0;
            struct nlist *plist;
            for (plist = ptable[i]; plist != NULL; plist = plist->next)
                printf("\tList nr %d: name: '%s', defn: '%s'\n", j++, plist->name, plist->defn);
        }
}
并打印结果:

printTable(hashtab);
给出:

哈希表索引90内容:
列表编号0:名称:“例程”,定义:“blabla”
清单1:名称:“请”,定义:“bla”

好的,
#定义例程101
?欢迎使用堆栈溢出。请尽快阅读页面。准备在SO上显示代码时,请避免使用制表符,建议的缩进通常为每个制表符4个空格(但只要保持一致,任何值都可以)。处理哈希冲突的策略有多种。一种是单步搜索哈希表以查找打开的插槽;另一种是启动哈希项的链接列表。对于后者,平均而言,您必须搜索列表中的N个/HASHSIZE项(如果没有哈希,则搜索N个项)。
printTable(hashtab);