首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >rle压缩算法c

rle压缩算法c
EN

Stack Overflow用户
提问于 2013-11-24 15:34:50
回答 4查看 8K关注 0票数 0

我必须在c中用转义字符(Q)做一个rle算法。

例如,如果我有一个输入,如:AAAAAAABBBCCCDDDDDDEFG

输出必须是:QA7BBBCCCQD6FFG

这就是我做的代码:

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>

void main()
{ 
    FILE *source = fopen("Test.txt", "r");
    FILE *destination = fopen("Dest.txt", "w");
    char carCorrente; //in english: currentChar
    char carSucc;     // in english: nextChar
    int count = 1;

    while(fread(&carCorrente, sizeof(char),1, source) != 0) {
        if (fread(&carCorrente, sizeof(char),1, source) == 0){
            if(count<=3){
                for(int i=0;i<count;i++){
                    fprintf(destination,"%c",carCorrente);
                }
            }
            else {
                    fwrite("Q",sizeof(char),1,destination);
                    fprintf(destination,"%c",carCorrente);
                    fprintf(destination,"%d",count);
                }
            break;
        }
        else fseek(source,-1*sizeof(char), SEEK_CUR);

        while (fread(&carSucc, sizeof(char), 1, source) != 0) {
            if (carCorrente ==  carSucc) {
                count++;
            } 
            else {
                if(count<=3){
                    for(int i=0;i<count;i++){
                        fprintf(destination,"%c",carCorrente);
                    }
                }
                else {
                    fwrite("Q",sizeof(char),1,destination);
                    fprintf(destination,"%c",carCorrente);
                    fprintf(destination,"%d",count);
                }

                count = 1;
                goto OUT;
            }
        }

OUT:fseek(source,-1*sizeof(char), SEEK_CUR); //exit 2° while
    }
}

问题是当我有这样的输入时:ABBBCCCDDDDDEFGD

在本例中,输出是:QB4CCCQD5FFDD

我不知道为什么:

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-11-24 16:32:14

没有必要像您所做的那样使用rewind来倒带,这里有一个代码,它是通过使用简单的逆流序列字符而编写的,而不是使用它。

C实现:

代码语言:javascript
复制
#include<stdio.h>
#include<stdlib.h>

void main()
{ 
    FILE *source = fopen("Test.txt", "r");
    FILE *destination = fopen("Dest.txt", "w");
    char currentChar;
    char seqChar;
    int count = 0;

    while(1) {
      int flag = (fread(&currentChar, sizeof(char),1, source) == 0); 

      if(flag||seqChar!=currentChar) {

         if(count>3) {
           char ch = 'Q';
           int k = count;
           char str[100];
           int digits = sprintf(str,"%d",count);
           fwrite(&ch,sizeof(ch),1,destination);
           fwrite(&seqChar,sizeof(ch),1,destination);
           fwrite(&str,sizeof(char)*digits,1,destination);
         }
         else {
           for(int i=0;i<count;i++) 
              fwrite(&seqChar,sizeof(char),1,destination);
         }
         seqChar = currentChar;
         count =1;
      }

     else count++;

     if(flag)
       break;
    }

   fclose(source);
   fclose(destination);
}
票数 2
EN

Stack Overflow用户

发布于 2013-11-24 16:30:51

您的代码有各种问题。首先,我不确定你是否应该从文件中直接阅读。在您的示例中,最好先使用fgets将源字符串读入文本缓冲区,然后进行编码。(我认为在你的作业中,你只应该对字母进行编码。如果source是一个常规文本文件,它将至少有一个换行符。)

但是,让我们假设您需要直接从磁盘读取:您不需要倒退。您已经有了当前和下一个字符的两个变量。从磁盘读取下一个字符一次。在进一步阅读“下一个字符”之前,分配:

代码语言:javascript
复制
int carSucc, carCorr;             // should be ints for getc

carSucc = getc(source);           // read next character once before loop 
while (carSucc != EOF) {          // test for end of input stream
    int carCorr = next;           // this turn's char is last turn's "next"

    carSucc = getc(source);
    // ... encode ...
}

前进和后退使循环变得复杂。此外,如果第二次读取的字符为零,即已到达文件的末尾,会发生什么情况?然后回溯一次,然后进入第二个循环。这看起来好像不是故意的。

试着往前走,并使用上面的循环作为编码的基础。

票数 1
EN

Stack Overflow用户

发布于 2013-11-24 18:16:57

我认为您的方法的主要问题是,在多个不同的地方,您读取输入并在输入中查找,这太复杂了。RLE可以一次完成,不应该有必要去寻找以前的字符。解决这一问题的一种方法是将逻辑转换为查看前面的字符以及它们被重复了多少次,而不是试图展望未来的字符。例如:

代码语言:javascript
复制
int repeatCount = 0;
int previousChar = EOF;
int currentChar; // type changed to 'int' for fgetc input

while ((currentChar = fgetc(source)) != EOF) {
    if (currentChar != previousChar) {
        // print out the previous run of repeated characters
        outputRLE(previousChar, repeatCount, destination);
        // start a new run with the current character
        previousChar = currentChar;
        repeatCount = 1;
    } else {
        // same character repeated
        ++repeatCount;
    }
}
// output the final run of characters at end of input
outputRLE(previousChar, repeatCount, destination);

然后,您可以实现outputRLE来完成输出,以打印出字符c重复的count次数的运行(注意,count可以是0);下面是函数声明:

代码语言:javascript
复制
void outputRLE(const int c, const int count, FILE * const destination)

虽然通过将fwrite和两个fprintf组合成一个fprintf,您可以使用与当前代码相同的方式进行简化。另外,如果转义字符'Q'出现在输入中,或者运行10个或更多的重复字符,您可能想一想会发生什么。在outputRLE中处理这些案件。

代码中一个不相关的问题是,返回类型的main应该是int,而不是void

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20176338

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档