Atom原子C语言实现

Atom原子C语言实现

 

       在《C语言接口与实现》中,原子(atom)是这样定义的:它是一个指针,指向了一个唯一的、不可变得序列,序列中包含零或多个字节(字节值任意)。任一原子都只会出现一次。如果两个原子指向相同的位置,那么二者是相同的。优点是节省空间,因为任一序列都只会出现一次。

      按照该书的要求,实现了四个接口:

int AtomInit(void);
char *AtomNew(const char *str,size_t len);
char *AtomString(const char *str);
size_t AtomLength(const char *str);
         AtomInit是定义了一个全局变量g_ath,它指向了一个哈希表,当然该哈希为链式哈希,解决的冲突方法为拉链法。AtomNew函数是根据哈希值在哈希表中找到对应的桶,然后在该桶上添加原子项。AtomString只是调用了AtomNew函数而已,而AtomLength函数返回的是变量str的长度。

基本的数据结构如下:

#define MAX_ATOM_TABLE 1

struct Atom
{
   struct Atom *next;
   int len;
   char *str;
};

struct AtomTableHead
{
   int freenode;
   size_t st;
   struct Atom *buffer;
}g_ath;

总体设计图如下:


1 初始化

int atomInit()
{
   g_ath.freenode= 0;
   g_ath.st= MAX_ATOM_TABLE;
   g_ath.buffer= (struct Atom *)malloc(sizeof(struct Atom)*g_ath.st);
   if(!g_ath.buffer)
      return-1;
   memset(g_ath.buffer,0,g_ath.st*sizeof(structAtom));
   return0;
}

2 哈希函数

    为保证原子能均匀的分别在桶中,选择HASH函数非常有讲究的,通常情况下根据经验来处理哈希值。本文选用下面函数:

unsigned long hash(const char *name,size_t len)
{
	unsigned long h=(unsigned long)len;
	size_t step = (len>>5)+1;
	size_t i;
	for (i=len; i>=step; i-=step)
	    h = h ^ ((h<<5)+(h>>2)+(unsigned long)name[i-1]);
	return h;
}

3 添加原子

char *atomNew(const char *str,size_t len)
{
   unsigned long k = hash(str,len);
   struct Atom *temp,*head;
   temp =head = g_ath.buffer + (k & (g_ath.st-1));
   for(;temp;temp= temp->next)
   {
      if(temp->len== 0)
      {
         structAtom *slot = temp;
         temp= temp->next;
         while(temp)
         {
            if(temp->len== len)
            {
                if(!memcmp(temp->str,str,len))
                  returntemp->str;
            }
            temp= temp->next;
         }
         slot->len= len;
         slot->str= (char *)(slot - offsetof(struct Atom,str));
         memcpy(slot->str,str,len);
         slot->str[len]= '\0';

         returnslot->str;
      }
      if(temp->len== len)
      {
         if(!memcmp(temp->str,str,len))
            returntemp->str;
      }
   }
   size_t flen=len+sizeof(struct Atom)+1;
   struct Atom *newSlot = (struct Atom *)malloc(flen);
   memset(newSlot,0,sizeof(structAtom)+len+1);
   newSlot->len= len;
   size_t sz = offsetof(struct Atom,str);
   newSlot->str= (char *)(newSlot - sz );   //大端小端问题
   memcpy(newSlot->str,str,len);
   newSlot->str[len]= '\0';
   structAtom *tmp = head->next;
   head->next= newSlot;
   newSlot->next= tmp;
   returnnewSlot->str;
}

         考虑到链式管理,插入原子时是选择查在第一个原子的后面,如下图所示:

 

4 得到原子的长度

size_t atomLength(const char *str)
{
   size_t len = strlen(str);
   size_t k= hash(str,len);
   struct Atom *temp = g_ath.buffer + (k & (g_ath.st-1));
   for(;temp;temp=temp->next)
   {
      if(temp->len== len)
      {
         if(!memcmp(temp->str,str,len))
            returntemp->len;
      }
   }
   return 0;
}
            在开发中,原子是非常有用的,通常情况下,如果使用任意字节的序列作为索引(而不使用整数),那么可以将原子用作键。

 


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,我了解了您的问题。下面是用C语言实现广义表建立、查找、输出、取表头的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAXSIZE 100 //定义广义表中元素的最大长度 typedef struct GLNode{ int tag; //0表示原子,1表示子表 union { char data[MAXSIZE]; //原子结点的值 struct GLNode *sublist; //子表的指针 }atom; struct GLNode *next; //指向下一个广义表结点的指针 }GLNode, *GList; //建立广义表 GList createGList(char *s) { GList p, t, h = NULL; int k, len; len = strlen(s); for (int i = 0; i < len; ) { p = (GList)malloc(sizeof(GLNode)); if (!h) { //第一个结点 h = p; t = h; } else { t->next = p; t = p; } if (s[i] == '(') { p->tag = 1; //子表结点 int j = i + 1, cnt = 1; while (cnt) { j++; if (s[j] == '(') cnt++; else if (s[j] == ')') cnt--; } char *sub_s = (char *)malloc(sizeof(char) * (j - i - 1)); strncpy(sub_s, s + i + 1, j - i - 1); sub_s[j - i - 1] = '\0'; p->atom.sublist = createGList(sub_s); //递归创建子表 i = j + 1; } else { p->tag = 0; //原子结点 k = 0; while (s[i] != '(' && s[i] != ')' && s[i] != ',' && i < len) { p->atom.data[k++] = s[i++]; } p->atom.data[k] = '\0'; } p->next = NULL; } return h; } //查找广义表 GList searchGList(GList L, char *x) { GList p; if (!L) return NULL; if (L->tag == 0) { //原子结点 if (strcmp(L->atom.data, x) == 0) return L; else return NULL; } else { //子表结点 p = searchGList(L->atom.sublist, x); if (p) return p; else return searchGList(L->next, x); } } //输出广义表 void printGList(GList L) { if (!L) return; if (L->tag == 0) printf("%s", L->atom.data); else { printf("("); printGList(L->atom.sublist); printf(")"); } if (L->next) { printf(","); printGList(L->next); } } //取表头 GList getHead(GList L) { if (!L) return NULL; if (L->tag == 0) return NULL; //原子结点没有表头 else return L->atom.sublist; } int main() { char s[MAXSIZE]; printf("请输入广义表:"); scanf("%s", s); GList L = createGList(s); printf("广义表为:"); printGList(L); printf("\n请输入要查找的元素:"); scanf("%s", s); GList p = searchGList(L, s); if (!p) printf("未找到元素 %s\n", s); else printf("找到元素 %s\n", s); GList head = getHead(L); if (head) { printf("表头为:"); printGList(head); printf("\n"); } else { printf("广义表为原子结点,无法取表头\n"); } return 0; } ``` 示例输入: ``` (1,(2,3),4) 2 ``` 示例输出: ``` 请输入广义表:(1,(2,3),4) 广义表为:(1,(2,3),4) 请输入要查找的元素:2 找到元素 2 表头为:2 ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值