替換字符串中的空格


題目:實現一個函數,要求吧字符串中的所有空格替換成“%20”。例如“hello world "  ——>  ”hello%20world%20"

實際背景:在網絡編程中,如果URL參數中含有特殊的字符,如空格、'#'等,導致服務器端無法識別時,就把這些特殊的字符轉換成可以識別的字符。規則:%加上十六進制的ascii碼,例如‘#’的ascii碼是0x23(16進制),就替換成%23,看下圖地址欄中,輸入“hello#hao"

           

分析:

注意:在c語言中存字符串最后一位是認為”\0“的,例如a[] = "12",那么a的長度為3,a[0]='1',a[1]='2',a[2]='\0',‘\0’是空字符,其ascii碼為0如下圖。相比之下:b[] = {'1', '2'}長度則為2.

          

思路一:可以再造一個數組,遇到空格就替換成”%20“這樣就造成了空間的浪費,可以實現但不是最佳

思路二:

  • 從前往后:在原基礎上進行替換(當然前提是空間足夠),如果從前往后遇到空格就替換,必然會對原來的字符造成覆蓋,不可以實現。
  • 從后往前:如果倒着遇到空格就往后移動同時替換,那么如果全部是空格,那勢必造成時間復雜度為O(n2)的開銷。可以實現,但不是最佳

思路三:因為把空格替換為”%20“,每次替換多2個字符,因此可以統計出字符串中空格的總個數,然后新數組大小為  “原數組大小 + 2*空格數 ”。從后往前處理:遇到非空格,直接搬到后面,遇到空格替換為”%20“. 直到待插入位置指針和原數組為指針重合位置。圖示如下:

 參考代碼:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLEN 100
void ReplaceBlack(char *p)
{
  if (p != NULL)
  {
    int i, end, pos ,size_black = 0;
    size_t  lenold = strlen(p), lennew;
    
    for (i=0; i != lenold; i++)
    {
        if (p[i] == ' ')
            size_black++;
    }
    lennew = lenold + 2 * size_black;
    if(lennew > MAXLEN)
        return;
    pos = lennew-1;
    end = lenold-1;
    while(pos != end)
    {
        if (p[end] != ' ')
            p[pos--] = p[end--];
        else
        {
            p[pos--] = '0';
            p[pos--] = '2';
            p[pos--] = '%';
            end--;
        }
    }//while
  }
}

int main()
{
    char *a = (char*)malloc(sizeof(char) * MAXLEN);
    if(NULL != a)
    {
        strcpy(a, "hell world ");
        ReplaceBlack(a);
        printf("%s\n", a);
        free(a);
    }
    return 0;
}

運行結果:

這樣實現的時間復雜度為O(n),又不浪費多余的空間。

舉一反三:

有兩個排好序(升序)的兩個數組A1,A2,如何高效的把A2的元素復制到A1的后邊(假設A1后邊有足夠的空間)

思路相同

  • 先看看兩個數組總共的空間大小,知道了需要數組A1的總共的元素個數
  • A1和A2同時從后往前處理,比較大的放在A1新的最后位置
  • 重復處理,直到A2中沒有元素了,這是復制完了

參考代碼

#include <stdio.h>
#include <string.h>
int  ReplaceBlack(int *a, int *b, int lena, int lenb, int length)
{
    int i, token = 0;
    int total = lena + lenb;
    if (a != NULL && b != NULL && (total <= length))
    {
        lena--;
        lenb--;
        i = total - 1;
        while(lena != -1 && lenb != -1)
        {    
            if(a[lena] >= b[lenb])
                a[i--] = a[lena--];
            else
                a[i--] = b[lenb--];
        }
        while(lenb != -1)
            a[i--] = b[lenb--];

        token = 1;
    }
    return token;   
}

int main()
{
    int length = 100;
    int i, a[100] = {1, 2, 3, 5}, b[] = {0, 4, 7};
    int lena = 4, lenb = 3;
    if(0 != ReplaceBlack(a, b, lena , lenb, length))
        for(i = 0; i< lena+lenb; i++)
            printf("%d\n", a[i]);

    return 0;
}

 注意幾個技術細節問題

1.strlen與sizeof的區別與聯系

  • 兩者返回類型都是size_t
  • strlen是字符串函數,sizeof是運算符
  • sizeof可以把類型當做參數,例如sizeof(int),strlen()對象只能是指向字符串類型的指針
  • 數組做sizeof參數不退化,傳遞給strlen()就退化為指針了。例如char a[] = "12" sizeof(a) = 3*1 = 3,此時a指數組; strlen(a) = 3,此時a指指針

        數組作為參數傳遞給函數時,傳遞的是指針不是數組。例如fuc(char *a),在函數中計算sizeof(a) 是指針的大小4(32位系統)或8(64位系 統)

程序演示

#include <stdio.h>
#include <string.h>

void fuc1(char *p)
{
    printf("fuction:%s\n", p);
    printf("fuction:sizeof:%lu,strlen:%lu\n", sizeof(p), strlen(p));
}
int main()
{
    char d[] = "hello";
    printf("main:%s\n", d);
    printf("main:sizeof:%lu,strlen:%lu\n", sizeof(d), strlen(d));
    fuc1(d);
    return 0;
}

結果

      

  • sizeof在編譯時就決定了,而strlen()函數在計算時才得出

2. 動態數組和靜態數組的區別

聲明

    動態數組如:char *a = (char *)malloc(sizeof(char) * 100);  由程序員自己分配空間

    靜態數組如:char a[100];由操作系統非配空間

初始化

   在聲明中靜態數組是可以的,如:char a[100]=”hello",但是動態的不可以。

 

主要涉及到molloc()\free()的理解和堆棧,下邊地址介紹的相當詳細:

淺談C中的malloc和free:http://www.bccn.net/Article/kfyy/cyy/jszl/200608/4238.html

堆棧(百度百科):http://baike.baidu.com/view/93201.htm

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM