假设有一个有序的字符串链表,链表中的每个节点为一个单词,我们可以使用它来将单词插入到链表,同时不会导致重复,但这样带来的问题是搜索链表的时间会随着链表规模的的扩大而急剧增长。
那么如何缩短这个时间呢?不妨先看看下图:
如上图所看到的数据结构,它的思路是将整个链表分解成26×27个链表,第一个链表存放26个字母,作为一级链表,该链表每个节点还存放一个指针,指向二级链表,二级链表同样存放26个字母,每个节点包含了一个指向单词链表的指针。
单词的第一个字符在一级链表当中找到匹配项,找到匹配进入二级链表,将单词的第二个字符在二级链表找到匹配项,进入单词链表找到整个单词的匹配项。
首先先构造一级、二级、单词节点:
#include "stdio.h"
#include "string.h"
#include "ctype.h"
#include "malloc.h"
#define TRUE 1
#define FALSE 0
/*存放单词*/
typedef struct WORD{
char *word;
struct WORD *next;
}Word;
/*二级节点*/
typedef struct SECLIST{
char letter;
struct SECLIST *next;
Word *word_list;
}SecList;
/*一级节点*/
typedef struct FIRSTLIST{
char letter;
struct FIRSTLIST *next;
SecList *sec_list;
}FirList;
声明:
FirList *fir_cur_list;
SecList **sec_listp;
SecList *sec_cur_list;
Word **wordp;
Word *current_word;
接着是插入函数,该函数需传入指向整个链表根节点的指针和准备插入到链表中的单词.
/*新单词插入*/
int
concordance_insert(FirList **fir_listp,char *the_word)
{
int first_char;
int sec_char;
int comparison;
Word *new_word;
/*获取第一个字符并确保该字符有效*/
first_char = *the_word;
if (!islower(first_char))
{
return FALSE;
}
/*获取第二个字符并确保该字符有效*/
sec_char = *(the_word + 1);
if (!islower(sec_char))
{
return FALSE;
}
/*根据第一个字符在一级链表中找到匹配项,如果不存在,则创建一个新的节点并插入到一级链表当中*/
while ((fir_cur_list = *fir_listp)!= NULL && fir_cur_list ->letter next;
}
/*如果在一级链表当中,当前节点为null(即到链表的结尾)或者找到一个节点中的字符比第一个字符大的,*/
/*创建一个新的一级节点,该节点包含一个新的二级链表*/
if (fir_cur_list == NULL || fir_cur_list->letter > first_char)
{
FirList *new_list;
new_list = (FirList *)malloc(sizeof(FirList));
if (new_list == NULL)
{
return FALSE;
}
new_list->letter = first_char;
new_list->sec_list = NULL;
new_list->next = fir_cur_list;
*fir_listp = new_list;
/*需要将当前节点的指针指向新创建的节点,因为不管是新创建还是已存在的节点,*/
/*我们都需要知道指向这个节点的指针,方便我们作二级查找*/
fir_cur_list = new_list;
}
/*当前一级节点包含二级链表的根节点,根据第二个字符在二级链表找到匹配项*/
sec_listp = &fir_cur_list->sec_list;
while ((sec_cur_list = *sec_listp) != NULL && sec_cur_list->letter < sec_char)
{
sec_listp = &sec_cur_list->next;
}
/*如果在二级链表当中,当前节点为null(即到链表的结尾)或者找到一个节点中字符比第二个字符大的,*/
/*创建一个新的二级节点,该节点包含一个新的单词链表*/
if (sec_cur_list == NULL || sec_cur_list->letter > sec_char)
{
SecList *new_sec_list;
new_sec_list = (SecList *)malloc(sizeof(SecList));
if (new_sec_list == NULL)
{
return FALSE;
}
new_sec_list->letter = sec_char;
new_sec_list->word_list = NULL;
new_sec_list->next = sec_cur_list;
*sec_listp = new_sec_list;
sec_cur_list = new_sec_list;
}
/*当前二级节点包含单词链表的根节点,根据第the_word在单词链表找到匹配项*/
wordp = &sec_cur_list->word_list;
while ((current_word = *wordp)!= NULL)
{
comparison = strcmp(current_word->word,the_word);
if (comparison >= 0)
{
break;
}
wordp = ¤t_word->next;
}
/*如果当前单词节点不为0且比较结果等于,该单词已经存在于链表当中*/
if (current_word != NULL && comparison == 0)
{
return FALSE;
}
new_word = (Word *)malloc(sizeof(Word));
if (new_word == NULL)
{
return FALSE;
}
/*创建一个新的单词节点存放单词*/
new_word->word = (char *)malloc(strlen(the_word) + 1);
if (new_word->word == NULL)
{
return FALSE;
}
strcpy(new_word->word,the_word);
/*将新节点接入到链表当中*/
new_word->next = current_word;
*wordp = new_word;
return TRUE;
}
打印整个索引表:
/*打印整个索引表*/
void
printf_table(FirList **fir_listp)
{
while((fir_cur_list = *fir_listp) != NULL)
{
printf("%c",fir_cur_list->letter);
putchar('\n');
sec_listp = &fir_cur_list->sec_list;
while((sec_cur_list=*sec_listp) != NULL)
{
printf("%c",sec_cur_list->letter);
putchar('\n');
wordp = &sec_cur_list->word_list;
while((current_word = *wordp) != NULL)
{
printf("%s",current_word->word);
putchar('\n');
wordp = ¤t_word->next;
}
sec_listp=&sec_cur_list->next;
}
fir_listp = &fir_cur_list->next;
}
}
int
main()
{
char message[] = "ziqi";
FirList **listp;
FirList *root;
FirList list;
list.letter=' ';
list.next = NULL;
list.sec_list = NULL;
root = &list;
listp = &root;
concordance_insert(listp,message);
printf_table(listp);
return 0;
}
希望此文对你有帮助。