周六,小雨,写个字符压缩代码,来玩一下。
压缩示例:
a b b c c c d e e
a b 2 c 3 d e 2
a b b c c c d e f
a b 2 c 3 d e f
a
a
a b
a b
a a
a 2
a a a
a 3
代码:
#include <iostream>
#include <cassert>
using namespace std;
int compress(char *a, int nSize)
{
assert(a != NULL && nSize > 0);
char *p = new char[nSize];
assert(p != NULL);
int i = 0;
int j = 0;
int iTimes = 0;
for(i = 0; i < nSize - 1; ++i) // 下面有a[i + 1],故需要防止越界
{
if(a[i] != a[i + 1]) // 说明遇到了新字符a[i + 1], 该终止旧的了,退出累计
{
if(iTimes > 0) // 旧字符有iTimes+1个,要赋值了
{
p[j++] = a[i];
p[j++] = iTimes + 1 + '0';
iTimes = 0;
}
else // 旧字符a[i]的个数仅仅是1个,直接赋值
{
p[j++] = a[i];
}
}
else // 相等,则记录次数
{
++iTimes;
if(i == nSize - 2) // 相等的情况,如果持续到最后两个字符,则需要退出了, 否则没机会退出了(无下一次循环)
{
p[j++] = a[i];
p[j++] = iTimes + 1 + '0';
}
}
}
if(1 == nSize) // 元素个数为1时,不会走上述遍历,故单独处理
{
p[j++] = a[0];
}
if(nSize > 1 && a[nSize - 2] != a[nSize - 1]) // 最后两个元素不相等时,最后一个元素需要补上
{
p[j++] = a[nSize - 1];
}
nSize = j;
memcpy(a, p, nSize);
delete [] p; // 不是delete p啊
p = NULL;
return nSize;
}
void print(char a[], int n)
{
int i = 0;
for(i = 0; i < n; ++i)
{
printf("%c ", a[i]);
}
printf("\n");
}
void test1()
{
char a[] = {'a', 'b', 'b', 'c', 'c', 'c', 'd', 'e', 'e'};
int nSize = sizeof(a) / sizeof(a[0]);
print(a, nSize);
int nRet = compress(a, nSize);
print(a, nRet);
printf("\n");
}
void test2()
{
char a[] = {'a', 'b', 'b', 'c', 'c', 'c', 'd', 'e', 'f'};
int nSize = sizeof(a) / sizeof(a[0]);
print(a, nSize);
int nRet = compress(a, nSize);
print(a, nRet);
printf("\n");
}
void test3()
{
char a[] = {'a'};
int nSize = sizeof(a) / sizeof(a[0]);
print(a, nSize);
int nRet = compress(a, nSize);
print(a, nRet);
printf("\n");
}
void test4()
{
char a[] = {'a', 'b'};
int nSize = sizeof(a) / sizeof(a[0]);
print(a, nSize);
int nRet = compress(a, nSize);
print(a, nRet);
printf("\n");
}
void test5()
{
char a[] = {'a', 'a'};
int nSize = sizeof(a) / sizeof(a[0]);
print(a, nSize);
int nRet = compress(a, nSize);
print(a, nRet);
printf("\n");
}
void test6()
{
char a[] = {'a', 'a', 'a'};
int nSize = sizeof(a) / sizeof(a[0]);
print(a, nSize);
int nRet = compress(a, nSize);
print(a, nRet);
}
int main()
{
test1();
test2();
test3();
test4();
test5();
test6();
return 0;
}
测了一下,结果OK.
很显然, 这是压缩算法, 非膨胀操作, 故可以采用就地算法(原地算法), 如下:
#include <iostream>
#include <cassert>
using namespace std;
int compress(char *a, int nSize)
{
assert(a != NULL && nSize > 0);
int flag = 0;
if(nSize > 1 && a[nSize - 2] != a[nSize - 1]) // a[nSize - 2]可能会被破坏,导致后续的比较出现问题,所以,这里先比较
{
flag = 1;
}
int i = 0;
int j = 0;
int iTimes = 0;
for(i = 0; i < nSize - 1; ++i) // 下面有a[i + 1],故需要防止越界
{
if(a[i] != a[i + 1]) // 说明遇到了新字符a[i + 1], 该终止旧的了,退出累计
{
if(iTimes > 0) // 旧字符有iTimes+1个,要赋值了
{
a[j++] = a[i];
a[j++] = iTimes + 1 + '0';
iTimes = 0;
}
else // 旧字符a[i]的个数仅仅是1个,直接赋值
{
a[j++] = a[i];
}
}
else // 相等,则记录次数
{
++iTimes;
if(i == nSize - 2) // 相等的情况,如果持续到最后两个字符,则需要退出了, 否则没机会退出了(无下一次循环)
{
a[j++] = a[i];
a[j++] = iTimes + 1 + '0';
}
}
}
if(1 == nSize) // 元素个数为1时,不会走上述遍历,故单独处理
{
a[j++] = a[0];
}
if(1 == flag) // 最后两个元素不相等时,最后一个元素需要补上
{
a[j++] = a[nSize - 1];
}
nSize = j;
return nSize;
}
void print(char a[], int n)
{
int i = 0;
for(i = 0; i < n; ++i)
{
printf("%c ", a[i]);
}
printf("\n");
}
void test1()
{
char a[] = {'a', 'b', 'b', 'c', 'c', 'c', 'd', 'e', 'e'};
int nSize = sizeof(a) / sizeof(a[0]);
print(a, nSize);
int nRet = compress(a, nSize);
print(a, nRet);
printf("\n");
}
void test2()
{
char a[] = {'a', 'b', 'b', 'c', 'c', 'c', 'd', 'e', 'f'};
int nSize = sizeof(a) / sizeof(a[0]);
print(a, nSize);
int nRet = compress(a, nSize);
print(a, nRet);
printf("\n");
}
void test3()
{
char a[] = {'a'};
int nSize = sizeof(a) / sizeof(a[0]);
print(a, nSize);
int nRet = compress(a, nSize);
print(a, nRet);
printf("\n");
}
void test4()
{
char a[] = {'a', 'b'};
int nSize = sizeof(a) / sizeof(a[0]);
print(a, nSize);
int nRet = compress(a, nSize);
print(a, nRet);
printf("\n");
}
void test5()
{
char a[] = {'a', 'a'};
int nSize = sizeof(a) / sizeof(a[0]);
print(a, nSize);
int nRet = compress(a, nSize);
print(a, nRet);
printf("\n");
}
void test6()
{
char a[] = {'a', 'a', 'a'};
int nSize = sizeof(a) / sizeof(a[0]);
print(a, nSize);
int nRet = compress(a, nSize);
print(a, nRet);
}
int main()
{
test1();
test2();
test3();
test4();
test5();
test6();
return 0;
}
测了一下, 结果OK.
作为程序员, 尽可能考虑到各种性能, 并处理好各种边界和异常, 很重要。