前两天其他项目组的同学说他们项目中的IP黑白名单要用到trie树,于是我好奇也自己实现了一个IP trie树接口.
在这里保存一下,方便备份以后使用,同时欢迎纠错和交流,希望有大神能指教更高效的算法.
1.头文件如下(iptrie.h)
1 #ifndef _IP_TRIE_H_ 2 #define _IP_TIRE_H_ 3 4 #define SPLIT_SIGN "." 5 #define IP_BINARY_LEN 32 6 7 typedef struct ip_trie_node 8 { 9 struct ip_trie_node *child[2]; //two child node 10 }ip_trie_node; 11 12 ip_trie_node *create_iptrie_node(); 13 14 void insert_iptrie_node(ip_trie_node *root,char ip[]); 15 16 int select_iptrie_node(ip_trie_node *root,char ip[]); 17 18 #endif
2.c文件如下(iptrie.c)
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 5 #include "iptrie.h" 6 7 /* 8 *name: itobinary 9 * 10 *param: 11 * num: orignal number; binary_str: dest string; index: the binary str copy index 12 * 13 *return: 14 * void 15 */ 16 void itobinary(int num,char binary_str[],int index) 17 { 18 if(binary_str == NULL) 19 { 20 return; 21 } 22 23 int i,bit = 0x01; 24 for(i = 0; i < 8; i++) 25 {//conver integer to 8 bit binary str 26 if((num & bit) != 0) 27 {//oprater & is lower than != 28 binary_str[index + 7 - i] = '1'; 29 } 30 else 31 { 32 binary_str[index + 7 - i] = '0'; 33 } 34 35 bit <<= 1; //bit * 2 36 } 37 } 38 39 /* 40 *name: convert_ip_binary 41 * 42 *param: 43 * ip:orign ip string; binary_str:dest binary string 44 * 45 *return: 46 * void 47 */ 48 void convert_ip_binary(char ip[],char binary_str[]) 49 { 50 if(ip == NULL || binary_str == NULL) 51 { 52 return; 53 } 54 55 /*为确保正确性在进行转换之前可以进一步进行IP格式校验*/ 56 57 char *ip_sub = NULL; 58 int i,index =0; 59 60 ip_sub = strtok(ip,SPLIT_SIGN); //slit ip by . 61 62 itobinary(atoi(ip_sub),binary_str,index); 63 64 for(i = 0; i < 3; i++) 65 {//need to ip legal detect to pretend error 66 ip_sub = strtok(NULL,SPLIT_SIGN); 67 68 index += 8; 69 itobinary(atoi(ip_sub),binary_str,index); 70 } 71 72 } 73 74 /* 75 *name: create_iptrie_node 76 * 77 *return: 78 * new ip trie node 79 */ 80 ip_trie_node *create_iptrie_node() 81 { 82 ip_trie_node *node = (ip_trie_node *)calloc(1,sizeof(ip_trie_node)); 83 84 if(node == NULL) 85 { 86 perror("create ip trie node error -- calloc"); 87 } 88 else 89 { 90 node->child[0] = NULL; 91 node->child[1] = NULL; 92 } 93 94 return node; 95 } 96 97 /* 98 *name: insert_iptrie_node 99 * 100 *param: 101 * root: trie root; ip: orignal ip string 102 * 103 *return: 104 * void 105 * 106 *notice: 107 * this function call strtok it will change input ip 108 * so if input ip need to use at other position 109 * you shold input a copy of ip 110 */ 111 void insert_iptrie_node(ip_trie_node *root,char ip[]) 112 { 113 if(root == NULL) 114 { 115 printf("trie have not init\n"); 116 117 return; 118 } 119 120 if(ip == NULL) 121 { 122 return; 123 } 124 125 char binary_str[IP_BINARY_LEN + 1]; 126 int i,child_index; 127 128 memset(binary_str,0,IP_BINARY_LEN + 1); 129 130 convert_ip_binary(ip,binary_str); //to binary string 131 132 for(i = 0; i < IP_BINARY_LEN; i++) 133 { 134 child_index = binary_str[i] - '0'; //child is 0 or 1 135 if(root->child[child_index] == NULL) 136 { 137 root->child[child_index] = create_iptrie_node(); 138 } 139 140 root = root->child[child_index]; 141 } 142 } 143 144 /* 145 *name: select_iptrie_node 146 * 147 *param: 148 * root: trie root; ip: orignal ip string 149 * 150 *return: 151 * 0 :not find; 1:find 152 * 153 *notice: 154 * this function call strtok it will change input ip 155 * so if input ip need to use at other position 156 * you shold input a copy of ip 157 */ 158 int select_iptrie_node(ip_trie_node *root,char ip[]) 159 { 160 if(root == NULL) 161 { 162 printf("trie have not init\n"); 163 return 0; 164 } 165 166 if(ip == NULL) 167 { 168 return 0; 169 } 170 171 int i; 172 char binary_str[IP_BINARY_LEN + 1]; 173 174 memset(binary_str,0,IP_BINARY_LEN + 1); 175 176 convert_ip_binary(ip,binary_str); //to binary string 177 178 int child_index; 179 for(i = 0; i < IP_BINARY_LEN; i++) 180 { 181 child_index = binary_str[i] - '0'; 182 183 if(root->child[child_index] == NULL) 184 { 185 return 0; 186 } 187 188 root = root->child[child_index]; 189 } 190 191 return 1; 192 }
3.main.c如下(测试程序)
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 #include "iptrie.h" 5 6 7 int main() 8 { 9 char sip[16]; 10 char dip[16]; 11 int i = 0; 12 int isfind = 0; 13 ip_trie_node *root = create_iptrie_node(); 14 15 while(1) 16 { 17 printf("insert a ip:\n"); 18 scanf("%s",sip); 19 insert_iptrie_node(root,sip); 20 21 printf("query a ip:\n"); 22 scanf("%s",dip); 23 isfind = select_iptrie_node(root,dip); 24 if(isfind == 1) 25 { 26 printf("find\n"); 27 } 28 else 29 { 30 printf("not find\n"); 31 } 32 } 33 }
4.Makefile (linux下编译)
CC = gcc CFLAG = -g INC = -I./ target:Iptrie Iptrie:iptrie.o main.c $(CC) $(CFLAG) $(INC) -o $@ $^ iptrie.o:iptrie.c $(CC) -c $< clean: rm *.o Iptrie