c语言去字符串重复元素,使用C语言去掉字符串集合重复元素

这篇博客介绍如何在C语言中手动实现去除字符串集合的重复元素,通过冒泡排序和二叉树插入两种方法。作者强调虽然在实际软件工程中使用现成的map更好,但自己实现能提升编程能力。

有一种最直接的方法可以去掉一个集合中重复的元素,这种方法据说就是“交给下面去做”,然而有时候,你自己动手去做一下也是不错的。如果交给下面去做,最直接的选择就是使用map,在java中,我们有HashMap,TreeMap等等实现了map接口的类可用,c++中,同样有STL的同类集合可以使用,在各类高级语言中,就更不必说了,然而在c中,就没有那么幸运了,很多东西需要你来自己实现。

根据《C语言内力修炼与软件工程》,用c语言自行实现这个东西,其实对于软件工程而言没有必要,然而可以训练一下自己,增加一些内力。我不认为自己是个高手,更非大侠,然而因为我懂得少,只能自己重新来做,真恨自己没有在5年前多学习一些编程语言。

先来简单分析一下需求,就是一个字符串集合中,去掉重复的字符串,换句话说就是每一个字符串只保留一个。题目没有说是否保持原有的字符串输入顺序,作为完美主义的我,我还是将其当成了一个隐含的需求。那么下一步就是将问题进行简化和转化,如果我们能将这一堆字符串进行排序,那么最终遍历这个排过序的字符串集合,发现和前一个相同的字符串就跳过不输出,对于排序,再简单不过了,至少N中排序算法,本文不讨论各种排序算法,只使用最简单的冒泡排序来分析。那么怎么保留原有的输入序呢?这也很简单,就是在排序元素中增加一个指向原有序的指针即可,另外还有一种方法,那就是排序过程仅仅是一个删除重复元素的过程,而不影响原有的输入序列,这个动态行为可以用二叉树的插入来实现,或者其它的AVL树以及红黑树都可以,本文不会去谈这几棵树的特性,只是用最简单的排序二叉树来分析。

我们知道,在二叉树插入中,首先要进行一次查找,现在要做的是,如果没有找到相同的,则插入,如果找到了相同的,则不插入,同时为该元素置入删除标识。代码如下:

//

// main.c

// dup-del

//

// Created by ya zhao on 11-12-17.

// Copyright 2011年 __MyCompanyName__. All rights reserved.

//

#include

#include

struct sorted_order_str_map_with_thread {

char *sorted_order_str; //保存排序后的字符串

char *normal_order_str; //保存原始字符串

int tag; //指示是否要删除

struct sorted_order_str_map_with_thread *self; //指向原始的位置

};

void sort(struct sorted_order_str_map_with_thread smwt[], const int size,

int (*cmp)(void *, void *),

void (*swap)(void *q1, void *q2));

int cmp_node(void *, void *);

//比较函数,如果相同则将其tag位设置为0,标示要删除

int cmp_node(void *q1, void *q2)

{

int res;

struct sorted_order_str_map_with_thread *cmp1, *cmp2;

cmp1 = (struct sorted_order_str_map_with_thread*)q1;

cmp2 = (struct sorted_order_str_map_with_thread*)q2;

res = strcmp(cmp1->sorted_order_str, cmp2->sorted_order_str);

if (res == 0) {

struct sorted_order_str_map_with_thread *p = cmp2->self;

p->tag = 0;

}

return res;

}

//交换函数,不光要交换元素,还要交换其self指针

void swap_node(void *q1, void *q2)

{

struct sorted_order_str_map_with_thread *swp1, *swp2,*temp;

char *strTemp;

swp1 = (struct sorted_order_str_map_with_thread*)q1;

swp2 = (struct sorted_order_str_map_with_thread*)q2;

strTemp = swp1->sorted_order_str;

temp = (swp1->self);

swp1->sorted_order_str = swp2->sorted_order_str;

swp1->self = swp2->self;

swp2->sorted_order_str = strTemp;

swp2->self = temp;

}

//标准冒泡排序

void sort(struct sorted_order_str_map_with_thread smwt[], const int size,

int (*cmp)(void *q1, void *q2),

void (*swap)(void *q1, void *q2))

{

int flag = 1;

for (int i = 0; i < size - 1; i ++) {

flag = 1;

for (int j = 0; j < size - i - 1; j ++) {

int res = 0;

if ((res = cmp(&smwt[j], &smwt[j+1])) > 0) {

swap(&smwt[j], &smwt[j+1]);

flag = 0;

}

}

if (flag == 1)

break;

}

}

int main (int argc, const char * argv[])

{

int i = 0;

//为了简化,下面使用了最恶心的初始化方法。方便复制粘贴

struct sorted_order_str_map_with_thread smwt[20] = {{NULL, NULL, 0 NULL}};

smwt[0].sorted_order_str =smwt[0].normal_order_str = "323";

smwt[0].self = &smwt[0];

smwt[0].tag = 1;

smwt[1].sorted_order_str = smwt[1].normal_order_str="223";

smwt[1].self = &smwt[1];

smwt[1].tag = 2;

smwt[2].sorted_order_str =smwt[2].normal_order_str= "723";

smwt[2].self = &smwt[2];

smwt[2].tag = 3;

smwt[3].sorted_order_str =smwt[3].normal_order_str= "823";

smwt[3].self = &smwt[3];

smwt[3].tag = 4;

smwt[4].sorted_order_str =smwt[4].normal_order_str= "123";

smwt[4].self = &smwt[4];

smwt[4].tag = 5;

smwt[5].sorted_order_str =smwt[5].normal_order_str= "423";

smwt[5].self = &smwt[5];

smwt[5].tag = 6;

smwt[6].sorted_order_str =smwt[6].normal_order_str= "123";

smwt[6].self = &smwt[6];

smwt[6].tag = 7;

smwt[7].sorted_order_str =smwt[7].normal_order_str= "723";

smwt[7].self = &smwt[7];

smwt[7].tag = 8;

smwt[8].sorted_order_str = smwt[8].normal_order_str="523";

smwt[8].self = &smwt[8];

smwt[8].tag = 9;

smwt[9].sorted_order_str =smwt[9].normal_order_str= "823";

smwt[9].self = &smwt[9];

smwt[9].tag = 10;

sort(smwt, 10, cmp_node, swap_node);

//下面使用了最恶心的输出,经典###

for (i = 0; i< 10; i++) {

printf("###:%s tag:%d\n", smwt[i].normal_order_str, smwt[i].tag);

}

for (i = 0; i< 10; i++) {

printf("@@@:%s tag:%d\n", smwt[i].sorted_order_str, smwt[i].tag);

}

for (i = 0; i< 10; i++) {

if (smwt[i].tag != 0){

printf("@@@&&:%s\n", smwt[i].normal_order_str);

}

}

return 0;

}

下面的一种方法使用了标准的二叉树插入,注意,插入仅仅是为了删除重复元素,实际上,各种语言各种库的标准Map实现很多也是使用了树,比如java.util中的TreeMap就是使用了红黑树。下面直接给出代码,基于排序二叉树的代码:

//

// main.c

// test-xcode

//

// Created by ya zhao on 11-12-17.

// Copyright 2011年 __MyCompanyName__. All rights reserved.

//

#include

#include

#include

struct string_node {

char *string;

int tag; //标示是否被删除

};

//标准排序二叉树

struct string_tree {

struct string_node *strn;

struct string_tree* left,*right;

};

struct string_tree *add_node(struct string_tree *, struct string_node *str, int (*cmp)(struct string_node *, struct string_node *));

int normalcmp(struct string_node *, struct string_node *);

//简单的字符串比较

int normalcmp(struct string_node *n1, struct string_node *n2)

{

return strcmp (n1->string,n2->string);

}

int main(int argc, char **argv)

{

int j = 0;

for (j = 0; j < 1; j++) {

struct string_tree *root;

struct string_node str[9] = {{"123",1},{"456",1},{"234",1},{"123",1},{"347",1},{"129",1},{"888",1}, {"568",1}, {"456",1}};

root = NULL;

int i = 0;

while (i<9) {

root = add_node(root, &str[i], normalcmp);

i ++;

}

i=0;

while (i<9){

if (str[i].tag) {

printf("&&&:%s\n", str[i].string);

}

i++;

}

}

return 0;

}

struct string_tree *add_node(struct string_tree *p, struct string_node *new, int (*cmp)(struct string_node *n1, struct string_node *n2))

{

int cmp_ret;

if (p == NULL) {

p = (struct string_tree *)calloc(1, sizeof(struct string_tree));

p->strn = (struct string_node*)calloc(1, sizeof(struct string_node));

memcpy(p->strn, new, sizeof(struct string_node));

p->left = p->right = NULL;

} else if ((cmp_ret = cmp(new, p->strn)) == 0) {

new->tag =0;

} else if (cmp_ret < 0) {

p->left = add_node(p->left, new, cmp);

} else {

p->right = add_node(p->right, new, cmp);

}

return p;

} 经过测试,自己实现的上述算法效率还可以,当然这里不该去比较效率,留下个思路即可,在没有库可用的情况下,也可以自己实现它。在现实中,特别是在软件工程中,还是使用现成的map比较好。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值