ASCII表的简要记法

ASCII表


 

分析此表:

 

1.      此表前三列不经常用,故只需记住前三列中四个特别的,其为:

 


名字

用途

二进制(B)

十六进制(H)

十进制(D)

LF

软回车

0000,1010

 0A

10

CR

回车

0000,1101

0D

13

ESC

退出

0001,1011

1B

27

SP

空格

0010,0000

 20

32


 

2.      后五列经常用,得记住,不可单一的记某个数,应记住去除前三列后的整个表。我的方法是这样的。

 

首先记住这三个:

 


名字

十进制(D)

十六进制(H)

1

49

31

A

65

41

a

97

61


 

对此表分析:为什么不把十六进制为51的Q加入进去。

               答:记忆多余,Q可根据英文字母的顺序写出来。

 

总结:1、A、a只能帮我们推算并记住数字及字母在表中的位置,而表中特殊的字符却不方便记忆。

 

3.针对2的总结,就提出了问题,怎么记忆其他的特殊字符。

我的方法是这样的:

 

1)、先看第四列阿拉伯数字下的特殊字符,分别是 : ; <  =  > ?注意其排列,再看键盘你会发现他的特点,只要别忘了  中间加了=

 

2)、101列中的[  \  ]刚好对应着英文大写的符号。同样结合键盘记忆。

 

3)、111列中的{  |  }配合键盘与[  \  ]的位置记忆。

 

4)、特殊记忆,A的上面有@ ,a上面有、 ;101,1110与101,1111的字符;~ 与DEL

 

 

 

注意:记忆时装的是整个图形,最好不要单独分开记忆。

 

 

 

我的观点就是这些,有点乱,呵呵,但愿能明白。

 

 

 

 

给自己的警告:记忆东西要讲方法,不能死背。

              要仔细观察,发现规律。

 


<think>我们被要求使用C语言实现哈希对字符串的操作,特别是去重。但根据引用内容,哈希可以用于快速查找和存储字符串。在字符串去重中,我们可以利用哈希来记录已经出现过的字符串(或字符),从而实现高效的去重。 然而,用户之前的问题是关于字符串去重,而本次问题则更广泛:如何在C语言中使用哈希对字符串进行操作(包括去重、统计等)。因此,我们将重点介绍哈希的实现,并展示如何利用哈希进行字符串去重。 根据引用,我们注意到: 引用[1]给出了哈希的基本结构(开散列法)和数据结构定义。 引用[2]展示了如何遍历哈希。 引用[3]说明了哈希的基本原理:通过哈希函数根据关键字计算地址。 引用[4]给出了一种哈希函数的例子(间隔取字符)。 因此,我们将: 1. 设计一个简单的哈希结构(开散列法)。 2. 实现哈希函数(这里我们使用一个经典的字符串哈希函数,比如djb2)。 3. 实现插入和查找操作。 4. 利用哈希实现字符串去重:遍历字符串的每个字符(或单词,但这里用户之前是字符去重,我们以字符为例,但也可以扩展到单词),使用哈希记录已经出现过的字符,只保留第一次出现的字符。 注意:字符串去重有两种常见情况:字符去重和单词去重。由于用户之前的问题是关于字符去重,我们将以字符去重为例,但方法可以推广。 步骤: 1. 定义哈希结构(参考引用[1]): - 哈希由多个槽(bucket)组成,每个槽是一个链,链的节点存储键(这里键是字符,但字符用整数示,所以我们实际上可以用整数作为键,但为了通用性,我们也可以存储字符串,但字符去重时,我们只需要存储字符的ASCII值,所以可以简化)。 - 但是,为了展示字符串操作,我们可以设计一个存储字符串的哈希,然后用于单词去重。不过用户之前是字符去重,所以这里我们考虑两种: a) 字符去重:键是字符(一个字符,所以可以用整数示) b) 字符串(单词)去重:键是字符串(需要动态分配内存) 考虑到用户之前的问题是关于字符去重,而引用中提到的哈希是针对字符串的,为了统一,我们这里先实现一个针对字符串(以'\0'结尾的字符数组)的哈希,然后用于字符串去重(即整个字符串作为元素去重,比如一个字符串数组,去除重复的字符串)?但用户之前是单个字符串内部的字符去重。 因此,我们需要明确:用户可能希望用哈希实现单个字符串内字符的去重,或者也可能是多个字符串的去重(即一个字符串数组,去除重复的字符串)。 由于问题描述是“对字符串进行操作”,我们考虑两种情况: 情况1:单个字符串内字符去重(如"hello"->"helo") 我们可以使用一个哈希集合(HashSet)来记录出现过的字符。由于字符数量有限(256个),我们可以直接使用一个大小为256的数组作为简单的哈希(数组下标就是字符的ASCII值)。但是,如果为了展示通用的哈希实现,我们可以用哈希结构。 情况2:字符串数组去重(如{"hello", "world", "hello"} -> {"hello", "world"}) 由于引用中提供的哈希结构是针对字符串(char*)的,所以我们先实现情况2:字符串数组去重。然后,我们也可以展示如何用哈希实现情况1(虽然情况1用数组更简单,但为了演示哈希,我们可以用哈希来存储字符)。 但是,注意引用[1]中的哈希结构体定义: typedef struct _htItem { struct _htItem *next; char *key_string; uint fid; // 记录值(这里我们可以用来记录出现次数等) } htItem; 我们计划: 1. 设计哈希的基本操作(创建、插入、查找、销毁)。 2. 使用哈希实现字符串数组去重:遍历数组,将每个字符串插入哈希,如果已经存在则跳过,否则加入结果数组。 3. 使用哈希实现单个字符串内字符去重:遍历字符串,对每个字符,将其视为一个长度为1的字符串,插入哈希,如果已存在则跳过,否则保留。 但是,对于单个字符串的字符去重,用哈希(链实现)显然比直接使用数组(visited数组)效率低,因为需要计算哈希值、处理冲突等。但为了演示,我们仍实现。 我们选择实现一个通用的字符串哈希(键为字符串),然后用于两种情况: - 对于字符串数组去重:键就是每个字符串。 - 对于单个字符串的字符去重:我们将每个字符转换为一个长度为2的字符串(第一个字符为原字符,第二个为'\0')作为键。 步骤: 一、定义哈希结构和函数 1. 哈希节点(htItem): - 键(key_string):字符串(需要动态分配内存存储,因为原字符串可能被修改) - 值(这里我们不需要存储额外信息,所以可以省略,但为了通用,我们保留一个整数域,比如可以存储出现次数) - 指向下一个节点的指针 2. 哈希:实际上是一个指向指针数组的指针(每个指针指向一个链),我们还需要记录哈希的大小(桶的数量)。 3. 哈希函数:我们使用一个经典的字符串哈希函数(djb2): unsigned long hash_function(char *str) { unsigned long hash = 5381; int c; while ((c = *str++)) hash = ((hash << 5) + hash) + c; // hash * 33 + c return hash; } 4. 基本操作: - 创建哈希:初始化一个固定大小的指针数组(初始为NULL) - 插入:计算哈希值,取模得到桶索引,然后在链中查找是否已经存在相同的键(字符串比较),如果存在则返回已存在;如果不存在,则在链头部或尾部插入新节点。 - 查找:计算哈希值,找到桶,然后遍历链比较字符串。 - 销毁:释放所有节点和哈希。 二、实现字符串数组去重 三、实现单个字符串内字符去重(将字符转换为字符串) 但是,由于单个字符串内字符去重用哈希效率不高,而且实现复杂,我们这里主要展示字符串数组去重,然后简要说明如何用于字符去重。 由于时间限制,我们实现一个简化版的哈希(固定大小,不考虑动态扩展),并实现插入和查找。 具体代码实现: 步骤: 1. 定义哈希节点和哈希结构。 2. 实现哈希函数。 3. 实现初始化哈希函数。 4. 实现插入函数:如果键已存在,则返回0;否则插入新节点,返回1。 5. 实现查找函数。 6. 实现销毁哈希。 然后,我们写一个函数,使用哈希对字符串数组去重。 注意:字符串数组去重后,我们需要返回一个新的字符串数组(不含重复元素)。由于要去重,我们遍历原数组,使用哈希检查每个字符串,如果未出现过,则将其添加到新数组中。 示例: 输入:char *arr[] = {"hello", "world", "hello", "world", "!"}; 输出:{"hello", "world", "!"} (顺序保持第一次出现的顺序) 我们使用插入顺序?哈希本身不保证顺序,但我们可以按遍历顺序将第一次出现的字符串加入新数组,这样就是原顺序。 代码结构: 1. 数据结构定义: typedef struct HashNode { char *key; struct HashNode *next; } HashNode; typedef struct { HashNode **buckets; // 桶数组 int size; // 桶的数量 } HashTable; 2. 哈希函数(使用djb2): #define TABLE_SIZE 1000 3. 创建哈希: HashTable *create_table(int size) { HashTable *table = malloc(sizeof(HashTable)); table->size = size; table->buckets = calloc(size, sizeof(HashNode*)); return table; } 4. 插入操作(如果不存在则插入,并返回1;存在则返回0): int insert(HashTable *table, char *key) { // 计算桶索引 unsigned long index = hash_function(key) % table->size; HashNode *node = table->buckets[index]; // 遍历链 while (node) { if (strcmp(node->key, key) == 0) { return 0; // 已存在 } node = node->next; } // 不存在,创建新节点(头插法) HashNode *new_node = malloc(sizeof(HashNode)); new_node->key = strdup(key); // 复制字符串 new_node->next = table->buckets[index]; table->buckets[index] = new_node; return 1; } 5. 销毁哈希:释放所有节点和。 6. 字符串数组去重函数: char **remove_duplicates(char **array, int length, int *result_length) { HashTable *table = create_table(TABLE_SIZE); char **result = malloc(length * sizeof(char*)); int count = 0; for (int i = 0; i < length; i++) { if (insert(table, array[i])) { // 第一次出现,添加到结果 result[count++] = strdup(array[i]); } } *result_length = count; destroy_table(table); return result; } 7. 注意:使用后需要释放结果数组(每个字符串和数组本身)。 但是,由于用户之前的问题是关于单个字符串去重(字符去重),我们也可以用一个哈希来存储字符(将字符当作字符串): char *remove_duplicate_chars(char *str) { // 创建一个哈希 HashTable *table = create_table(256); // 桶的数量为256,因为字符只有256种可能 int len = strlen(str); char *result = malloc(len+1); int p = 0; for (int i=0; i<len; i++) { // 将当前字符转换为字符串(临时构造一个字符串) char char_str[2] = {str[i], '\0'}; if (insert(table, char_str)) { result[p++] = str[i]; } } result[p] = '\0'; destroy_table(table); return result; } 但是,这种方法效率较低,因为每个字符都要构造一个临时字符串,而且哈希操作比直接使用数组(visited数组)慢。因此,对于字符去重,推荐使用数组标记法(如之前回答的方法1),这里只是为了演示哈希的用法。 由于实现一个完整的哈希代码较长,我们只展示关键部分。下面我们给出一个完整的示例,实现字符串数组去重。 完整代码示例(字符串数组去重):</think>### C语言使用哈希操作字符串的方法 在C语言中,哈希是实现高效字符串操作(如去重、统计等)的核心数据结构。它通过哈希函数将字符串映射到固定大小的数组中,实现$O(1)$平均时间复杂度的查找和插入。以下是详细实现方法: --- #### 一、哈希核心结构设计 ```c #include <stdio.h> #include <stdlib.h> #include <string.h> // 哈希节点结构 typedef struct HashNode { char *key; // 字符串键 int count; // 出现次数统计 struct HashNode *next; // 开散列冲突解决 } HashNode; // 哈希主体结构 typedef struct { int size; // 哈希大小 HashNode **buckets; // 桶数组 } HashTable; ``` --- #### 二、关键操作实现 ##### 1. 哈希函数设计(djb2算法) ```c unsigned long hash_function(const char *str) { unsigned long hash = 5381; int c; while ((c = *str++)) hash = ((hash << 5) + hash) + c; // hash * 33 + c return hash; } ``` - **原理**:通过多项式累积减少冲突[^3] - **特点**:均匀分布,时间复杂度$O(n)$ ##### 2. 哈希初始化 ```c HashTable* create_table(int size) { HashTable *table = malloc(sizeof(HashTable)); table->size = size; table->buckets = calloc(size, sizeof(HashNode*)); return table; } ``` ##### 3. 字符串插入/更新 ```c void insert_or_update(HashTable *table, const char *key) { unsigned long index = hash_function(key) % table->size; HashNode *node = table->buckets[index]; // 检查是否已存在 while (node) { if (strcmp(node->key, key) == 0) { node->count++; return; } node = node->next; } // 创建新节点 HashNode *new_node = malloc(sizeof(HashNode)); new_node->key = strdup(key); // 深拷贝字符串 new_node->count = 1; new_node->next = table->buckets[index]; table->buckets[index] = new_node; } ``` ##### 4. 字符串查找 ```c HashNode* search(HashTable *table, const char *key) { unsigned long index = hash_function(key) % table->size; HashNode *node = table->buckets[index]; while (node) { if (strcmp(node->key, key) == 0) return node; node = node->next; } return NULL; // 未找到 } ``` ##### 5. 哈希遍历 ```c void print_table(HashTable *table) { for (int i = 0; i < table->size; i++) { HashNode *node = table->buckets[i]; while (node) { printf("Bucket %d: %s (count: %d)\n", i, node->key, node->count); node = node->next; } } } ``` ##### 6. 内存释放 ```c void free_table(HashTable *table) { for (int i = 0; i < table->size; i++) { HashNode *node = table->buckets[i]; while (node) { HashNode *temp = node; node = node->next; free(temp->key); // 释放字符串内存 free(temp); // 释放节点内存 } } free(table->buckets); free(table); } ``` --- #### 三、应用场景示例 ##### 1. 字符串去重 ```c void string_deduplicate(char **strings, int count) { HashTable *table = create_table(128); for (int i = 0; i < count; i++) { insert_or_update(table, strings[i]); } // 输出去重结果 printf("Unique strings:\n"); for (int i = 0; i < table->size; i++) { HashNode *node = table->buckets[i]; while (node) { printf("%s\n", node->key); node = node->next; } } free_table(table); } ``` ##### 2. 词频统计 ```c void word_frequency(const char *text) { HashTable *table = create_table(256); char *token = strtok((char*)text, " ,.?!"); while (token) { insert_or_update(table, token); token = strtok(NULL, " ,.!?"); } print_table(table); free_table(table); } ``` --- #### 四、性能优化技巧 1. **动态扩容**:当负载因子 > 0.7时,重建哈希(双倍大小) ```c void resize_table(HashTable *table, int new_size) { // 创建新->迁移数据->销毁旧 } ``` 2. **素数大小**:使用素数作为大小减少冲突 3. **内存池**:预分配节点内存减少malloc调用 4. **优化哈希函数**:针对特定数据集定制哈希函数[^4] --- #### 五、典型应用场景 1. **字符串去重**:快速识别重复项 2. **拼写检查**:字典单词高速查找 3. **编译器符号**:变量名管理 4. **DNA序列分析**:k-mer计数 5. **缓存系统**:键值对快速检索 通过合理设计哈希函数和冲突解决机制,C语言哈希可实现接近$O(1)$时间复杂度的字符串操作,比传统方法(如嵌套循环)效率提升$O(n)$到$O(n^2)$[^1][^3]。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值