一。传统的list和linux中内核list结构对比,内核中的list更灵活
六程序如下
hashtable.h
#include "list.h" #include<string.h> #include<malloc.h> #define HASHTABEL_LEN 26 //以每个单词前面两个字母叠加作为hashtable的key值 struct hash_node { struct list_head openlist;//开链法用来索引的链表 int sum; char* word; }; struct hash_table { hash_node hashtable[HASHTABEL_LEN]; }; void init_hash_table(hash_table &hashtable) { int i; for (i=0;i<HASHTABEL_LEN;i++) { INIT_LIST_HEAD(&(hashtable.hashtable)[i].openlist); } } //将单词添加到hashtable中 void insert_list_node(hash_node *hashtable, hash_node *newnode) { hash_node *tmp; char *tmpword=newnode->word; hash_node* bucket=&hashtable[(*tmpword-'a')]; struct list_head* pos; list_for_each(pos,&(bucket->openlist)) { tmp=list_entry(pos,hash_node,openlist); if(strcmp(tmp->word,newnode->word)==0) { ++(tmp->sum); free(newnode->word); free(newnode); break; } else { list_add_tail(&(newnode->openlist),&(tmp->openlist)); break; } } if(pos==&(bucket->openlist)) { list_add_tail(&(newnode->openlist),&(bucket->openlist)); } }
list.h
#ifndef _LIST_H_ #define _LIST_H_ /* * Simple doubly linked list implementation. * * Some of the internal functions ("__xxx") are useful when * manipulating whole lists rather than single entries, as * sometimes we already know the next/prev entries and we can * generate better code by using them directly rather than * using the generic single-entry routines. */ struct list_head { struct list_head *next, *prev; }; #define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name) #define INIT_LIST_HEAD(ptr) do { \ (ptr)->next = (ptr); (ptr)->prev = (ptr); \ } while (0) /* * Insert a _new entry between two known consecutive entries. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static inline void __list_add(struct list_head *_new, struct list_head *prev, struct list_head *next) { next->prev = _new; _new->next = next; _new->prev = prev; prev->next = _new; } /** * list_add - add a _new entry * @_new: _new entry to be added * @head: list head to add it after * * Insert a _new entry after the specified head. * This is good for implementing stacks. */ static inline void list_add(struct list_head *_new, struct list_head *head) { __list_add(_new, head, head->next); } /** * list_add_tail - add a _new entry * @_new: _new entry to be added * @head: list head to add it before * * Insert a _new entry before the specified head. * This is useful for implementing queues. */ static inline void list_add_tail(struct list_head *_new, struct list_head *head) { __list_add(_new, head->prev, head); } /* * Delete a list entry by making the prev/next entries * point to each other. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static inline void __list_del(struct list_head *prev, struct list_head *next) { next->prev = prev; prev->next = next; } /** * list_del - deletes entry from list. * @entry: the element to delete from the list. * Note: list_empty on entry does not return true after this, the entry is in an undefined state. */ static inline void list_del(struct list_head *entry) { __list_del(entry->prev, entry->next); } /** * list_del_init - deletes entry from list and reinitialize it. * @entry: the element to delete from the list. */ static inline void list_del_init(struct list_head *entry) { __list_del(entry->prev, entry->next); INIT_LIST_HEAD(entry); } /** * list_empty - tests whether a list is empty * @head: the list to test. */ static inline int list_empty(struct list_head *head) { return head->next == head; } /** * list_splice - join two lists * @list: the _new list to add. * @head: the place to add it in the first list. */ static inline void list_splice(struct list_head *list, struct list_head *head) { struct list_head *first = list->next; if (first != list) { struct list_head *last = list->prev; struct list_head *at = head->next; first->prev = head; head->next = first; last->next = at; at->prev = last; } } /** * list_entry - get the struct for this entry * @ptr: the &struct list_head pointer. * @type: the type of the struct this is embedded in. * @member: the name of the list_struct within the struct. */ #define list_entry(ptr, type, member) \ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) /** * list_for_each - iterate over a list * @pos: the &struct list_head to use as a loop counter. * @head: the head for your list. */ #define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); \ pos = pos->next) /** * list_for_each_safe - iterate over a list safe against removal of list entry * @pos: the &struct list_head to use as a loop counter. * @n: another &struct list_head to use as temporary storage * @head: the head for your list. */ #define list_for_each_safe(pos, n, head) \ for (pos = (head)->next, n = pos->next; pos != (head); \ pos = n, n = pos->next) /** * list_for_each_entry - iterate over list of given type * @pos: the type * to use as a loop counter. * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define list_for_each_entry(pos, head, member, type) \ for (pos = list_entry((head)->next, type, member);\ &pos->member != (head);\ pos = list_entry(pos->member.next,type, member)) /** * list_for_each_entry_safe - 遍历时删除节点list_for_each_entry的一种安全用法 * @pos: the type * to use as a loop counter. * @n: another &struct list_head to use as temporary storage * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define list_for_each_entry_safe(pos, n, head, member, type) \ for (pos = list_entry((head)->next, type, member), n = pos->member.next;\ &pos->member != (head);\ pos = list_entry(n, type, member), n = pos->member.next) #endifhashtabletest.h
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<ctype.h> #include<malloc.h> #include "hashtable.h" #include"list.h" #include<iostream> using namespace std; #define FILE_NAME_MAX_LEN 256 /* the max length of the file */ //#define HASHTABEL_LEN 26 /* the length of hash table, cause there are 26 low case letters*/ #define SUCCESS 0 /* file operation flag */ #define FAILURE 1 /*getword function: get the words in the file */ int getword(FILE *fp, char **word_temp) { int ch; unsigned long num; num=0; while(!feof(fp)) { ch=fgetc(fp); if(isalpha(ch)) { num++; break; } } while (!feof(fp)) { ch = fgetc(fp); if (isalpha(ch)) { num++; } else { break; } } if (!feof(fp)) { (void)fseek(fp,-(num+1),1); *word_temp = (char *)malloc(num+1); if (word_temp == NULL) { (void)fprintf(stdout,"Sorry, the memory space is full"); (void)fprintf(stdout,"Please input any key to exit the program\n"); (void)getchar(); exit(FAILURE); } (void)fgets(*word_temp,num+1,fp); (void)fseek(fp,1,1); return SUCCESS; } else { if (num != 0) { *word_temp = (char *)malloc(num+1); if (word_temp == NULL) { (void)fprintf(stdout,"Sorry,the memory space is full"); (void)fprintf(stdout,"Please input any key to exit program....\n"); (void)getchar(); exit(FAILURE); } (void)fseek(fp,-(num),SEEK_CUR); (void)fgets(*word_temp,num+1,fp); return SUCCESS; } } return FAILURE; } //保存 void save_hashtable_node(hash_table &hashtable) { hash_node *head, *tmp; struct list_head *pos, *q; int i; FILE *fp; char filename[50]; cout<<"请输入要输出的文件名"<<endl; cin.getline(filename,50); if((fp=fopen(filename,"w"))==NULL) { (void)fprintf(stdout,"Sorry, failure to open the file\n"); (void)fprintf(stdout,"Please input any key to exit the program\n "); (void)getchar(); (void)exit(FAILURE); } for (i=0;i<HASHTABEL_LEN;i++) { head=hashtable.hashtable+i; list_for_each_safe(pos,q, &(head->openlist)) { tmp=list_entry(pos, hash_node,openlist); (void)fprintf(fp,"%s,%d\r\n",tmp->word,tmp->sum); (void)list_del(pos); (void)free(tmp->word); (void)free(tmp); } } (void)fprintf(stdout,"file successfully saved \n"); fclose(fp); } //显示 void display_hashtable_node(hash_node *hashtable) { hash_node *head, *tmp; struct list_head *pos, *q; int i; (void) fprintf(stdout, "结果如下:\n"); for(i=0; i<HASHTABEL_LEN; i++) { head=hashtable+i; list_for_each_safe(pos, q,&(head->openlist)) { tmp=list_entry(pos, hash_node,openlist); (void)fprintf(stdout,"%s,%d\n",tmp->word,tmp->sum); } } } int main() { FILE *fp; hash_table hashtable; hash_node *_new; char *word_tmp; char filename[50]; cout<<"请输入要统计的文件名"<<endl; cin.getline(filename,50); fp=fopen(filename,"rb"); init_hash_table(hashtable); while(!feof(fp)) { if(getword(fp,&word_tmp)==SUCCESS) { _new=(hash_node *)malloc(sizeof(hash_node)); if(_new==NULL) { (void)fprintf(stdout,"Sorry,the memory space is full"); (void)exit(FAILURE); } _new->sum=1; //将单词转换成小写 int i=0; while (*(word_tmp+i)!='\0') { *(word_tmp+i)=tolower(*(word_tmp+i)); i++; } _new->word=word_tmp; insert_list_node(hashtable.hashtable,_new); } } fclose(fp); display_hashtable_node(hashtable.hashtable); save_hashtable_node(hashtable); fprintf(stdout,"please input any key to exit the program\n"); getchar(); return 0; }