c 反轉字元,演算法優化與實現

2021-10-05 10:04:02 字數 2743 閱讀 5386

c++反轉字元

這是我在leetcode上看見的題目

嘗試了幾種寫法,耗時均不同,這裡先說一下第一種演算法「交換法」

交換法反轉字元就是從尾部一直向前挪移:

如:abcd = dbca

這是第一次交換,第二次交換就是:

dcba

可以看到每次交換都是首位交換,以此向中心擴充套件,通俗易懂的說就是兩者之間向中心點靠攏,每次交換會交換兩個字元,所以交換時間是:o(s\2)

四個字元兩次就可以完成反轉

實現:宣告乙個函式,這裡leetcode使用的是vector容器,我們也一樣.

void reversestring(std::vector& s)

第二步編寫乙個迴圈:

注意迴圈條件是字元大小/2,因為上面說過每次交換是兩個字元

for(int i = 0;i

這裡我的寫法為了省掉記憶體開闢空間以及記憶體互動的方式,使用加減法來儲存要交換的字元,防止被覆蓋,因為字元也是ascii碼

s[i] += s[(s.size()-i)-1];

這裡說一下這段**

s[i]是指向從0開始的字元下標,比如abcd那麼現在下標就是a

s[(s.size()-i)-1]

這段**是算出字元尾部的座標,每次-i是為了下一次的移動,比如現在是d,那麼下次迴圈i是1,就是b與c的交換了.

最後的-1是為了跳過\0,c/c++裡對字元結尾的定義是\0,不能把\0放到首位,如果\0在首位c/c++會認為這就是這段字元的結束.

這裡+=是為了儲存第一位的值,比如a的ascii是97,d的ascii碼是100,那麼相加就是197

此時s[i]=197相當於儲存了兩個字元

s[(s.size()-i)-1] = s[i] - s[(s.size()-i)-1];

這段**就是把末尾的值減去s[i],也就是197-d的ascii碼就等於了a的ascii碼,這樣尾部就有了a

同時還需要把首部的值在減去末尾的值,因為末尾的值剛好是a,那麼197-a的ascii碼就等於了d

s[i] -= s[(s.size()-i)-1];

完整**:

可惜力扣那邊測試,我們的演算法還是比較慢的,這裡就要想想別的辦法,因為我們上面的演算法造成了一部分的計算,還有記憶體資料交換,還是比較耗時的

c++內建了一種函式move,這個函式的用法是直接將乙個值變成左值,也就是立即數的方式,直接跟著指令集去運算,那麼就可以直接不用記憶體的方式去做這些工作了

比如:int a = 10;

int b = 0;

b = a;

如果想要讓b=a,cpu需要到a的記憶體裡取資料,複製乙份資料然後再到b的記憶體位址裡,把資料寫入

這個過程比較繁瑣,但是move不一樣,這個函式可以把a裡的值直接變成左值返回

b = std::move(a)

則變成了:b = 10;

如果不實用move則會翻譯成:b = &a;

這裡不用指令集的方式表示,這樣表示更加的直觀,

彙編的方式就是:

move方式:

mov byte ptr ds:[b],10

非move方式:

mov ax, byte ptr ds:[a] //取出a的值

mov byte ptr ds:[b],ax //放入b中

這裡彙編是大致寫了一下,詳細可以去返彙編看一下

我們修改一下**加上move試試:

for(int i = 0;i

看下力扣測試:

速度一下快了很多,也證實了我們上面說的.有時候演算法固然重要,但是編譯優化也很重要,很多硬體加速就是這樣的方法,使用一些特定的指令集.

上面這套演算法因為有了move的方式,可以省略記憶體訪問,這裡我們就完全沒必要在進行運算了,直接用乙個記憶體變數來儲存臨時的值:

char _c = s[i];

s[i] = std::move(s[(s.size()-i)-1]);

s[(s.size()-i)-1] = std::move(_c);

因為不用計算,也不用去取位址,看一下力扣的測試:

如果你想更懶一點,你可以使用swap函式直接實現,不過這樣就丟失了這道題的意義了.

for(int i = 0;i

move的方式就是我在查閱c++的**時找到的加速方法,因為我發現c++提供的一些函式,或是c,提供的一些基礎函式總是比我們自己寫的要快,我一開始以為是他們的演算法比較好,後來我去查閱了一些glibc的**和c++的一些實現,發現內部內嵌彙編極多,都是使用彙編優化,還有一些編譯器指令優化比如move,雖然說可以調整優化編譯器等級,但是這些細節往往是最重要的.

swap函式的實現:

template inline

void _swap(_ty& _left, _ty& _right)

注意c++的實現裡有乙個inline宣告,這是乙個類似c語言的巨集展開的宣告

比如你的函式add

前面加上inline宣告以後,你在別處呼叫的時候,會直接變成實現**,省去了函式呼叫的棧儲存位址跳轉等等開銷. 這是c++特有的關鍵字

演算法 反轉字串與反轉單詞

題目 將字串內容進行倒置,比如 i like beijing.經過函式後變為 gnijied ekil i。解題思路 首先題目說的很明確,就是反轉字串,不是列印,也不是建立乙個新的字串,而是改變原資料,最簡單的思路就是將第乙個字元和最後乙個交換,第二個和倒數第二個交換,依次迴圈,函式可以返回乙個標誌...

Kmp字元匹配演算法優化C 實現

c 實現kmp字元匹配演算法的優化版 標頭檔案 kmpalgorithm.h ifndef kmpalgorithm h define kmpalgorithm h include include class kmpalgorithm int index kmp int pos 字元匹配函式 end...

python演算法 字串反轉與單鏈表的反轉

1.字串反轉 字串反轉有很多種方式,舉例其中常見的3種 a hello a reverse a 1 print a reverse b yangyangchi b list list b b list.reverse b reverse join b list print b reverse def...