用C++實現高效字元串操作

在計算機編程中,字元串操作是一種使用頻率極高的操作。因此,如何在C++中實現高效的字元串操作是每個程序員必須掌握的技能之一。本文將從多個方面詳細闡述如何用C++實現高效的字元串操作。

一、字元串的概念及常見操作

字元串是指多個字元組成的序列,在C++中常用char數組或std::string來表示字元串。常見的字元串操作包括:

1、字元串拼接。將兩個或多個字元串連接起來,可以使用+運算符或std::string的append方法。

std::string str1 = "Hello";
std::string str2 = "World";
// 使用+運算符
std::string str3 = str1 + str2;
// 使用append方法
str1.append(str2);

2、字元串查找。在一個字元串中查找是否包含另一個字元串,可以使用std::string的find方法。

std::string str = "Hello, world!";
if (str.find("world") != std::string::npos) {
    std::cout << "Found" << std::endl;
} else {
    std::cout << "Not found" << std::endl;
}

3、字元串分割。將一個字元串按照某個分隔符分割成多個子字元串,可以使用std::string的substr和find方法。

std::string str = "Hello,world,!";
std::vector<std::string> substrs;
std::string::size_type pos1 = 0, pos2 = 0;
while ((pos2 = str.find(",", pos1)) != std::string::npos) {
    substrs.push_back(str.substr(pos1, pos2 - pos1));
    pos1 = pos2 + 1;
}
substrs.push_back(str.substr(pos1));

二、字元串操作的效率問題

對於常規的字元串操作,直接使用std::string的方法或者使用char數組實現都可以滿足要求。但對於需要高效處理字元串的場景,需要考慮字元串操作的效率。

1、字元串拼接。直接使用+運算符或std::string的append方法會導致頻繁的動態內存分配和釋放,影響性能。可以使用std::stringstream或者char數組來優化。例如使用std::stringstream:

std::string str1 = "Hello";
std::string str2 = "World";
std::stringstream ss;
ss << str1 << str2;
std::string str3 = ss.str();

使用char數組:

std::string str1 = "Hello";
std::string str2 = "World";
char buf[100];
std::snprintf(buf, sizeof(buf), "%s%s", str1.c_str(), str2.c_str());
std::string str3 = buf;

2、字元串查找。std::string的find方法在查找過程中會使用暴力匹配演算法,時間複雜度為O(n*m),n和m分別為兩個字元串的長度。可以使用KMP演算法或Boyer-Moore演算法來優化。例如使用KMP演算法:

std::string str = "Hello, world!";
std::string pattern = "world";
std::vector<int> next(pattern.size(), -1);
for (int i = 1, j = -1; i < pattern.size(); ++i) {
    while (j >= 0 && pattern[j + 1] != pattern[i]) {
        j = next[j];
    }
    if (pattern[j + 1] == pattern[i]) {
        ++j;
    }
    next[i] = j;
}
for (int i = 0, j = -1; i < str.size(); ++i) {
    while (j >= 0 && pattern[j + 1] != str[i]) {
        j = next[j];
    }
    if (pattern[j + 1] == str[i]) {
        ++j;
    }
    if (j == pattern.size() - 1) {
        std::cout << "Found at " << i - j << std::endl;
        j = next[j];
    }
}

3、字元串分割。使用std::string的substr方法和find方法會導致頻繁的字元串拷貝和動態內存分配和釋放,影響性能。可以使用標準庫的std::regex來實現正則表達式匹配,或者手寫字元串分割演算法。例如使用手寫分割演算法:

std::string str = "Hello,world,!";
std::vector<std::string> substrs;
std::string::size_type pos1 = 0, pos2 = 0;
while ((pos2 = str.find(",", pos1)) != std::string::npos) {
    substrs.push_back(str.substr(pos1, pos2 - pos1));
    pos1 = pos2 + 1;
}
substrs.push_back(str.substr(pos1));

三、常用字元串庫的性能比較

不同的字元串庫在實現上有所不同,因此在性能上也有所差異。我們在一台64位Ubuntu系統上,使用g++編譯器比較了STL庫、Boost庫和folly庫的字元串拼接、查找和分割性能。代碼如下:

#include <iostream>
#include <chrono>
#include <vector>
#include <string>
#include <sstream>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <folly/String.h>

int main() {
// 字元串拼接
std::string str1 = "Hello";
std::string str2 = "World";
{
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
for (int i = 0; i < 1000000; ++i) {
std::stringstream ss;
ss << str1 << str2;
std::string result = ss.str();
}
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
std::cout << "std::stringstream: " << std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() << "us" << std::endl;
}
{
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
for (int i = 0; i < 1000000; ++i) {
char buf[100];
std::snprintf(buf, sizeof(buf), "%s%s", str1.c_str(), str2.c_str());
std::string result = buf;
}
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
std::cout << "std::snprintf: " << std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() << "us" << std::endl;
}
{
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
for (int i = 0; i < 1000000; ++i) {
std::string result = str1 + str2;
}
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
std::cout << "std::string: " << std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() << "us" << std::endl;
}
{
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
for (int i = 0; i < 1000000; ++i) {
std::string result = str1.append(str2);
}
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
std::cout << "std::string::append: " << std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() << "us" << std::endl;
}
{
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
for (int i = 0; i < 1000000; ++i) {
std::string result = folly::to<std::string>(str1, str2);
}
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
std::cout << "folly::to: " << std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() << "us" << std::endl;
}
// 字元串查找
std::string str = "Hello, world!";
std::string pattern = "world";
{
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
for (int i = 0; i < 1000000; ++i) {
std::size_t pos = str.find(pattern);
if (pos != std::string::npos) {
std::string result = str.substr(pos);
}
}
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
std::cout << "std::string::find and substr: " << std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() << "us" << std::endl;
}
{
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
for (int i = 0; i < 1000000; ++i) {
std::vector<std::string> substrs;
boost::split(substrs, str, boost::is_any_of(","));
for (const auto& substr : substrs) {
if (substr == pattern) {
std::string result = substr;
}
}
}
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
std::cout << "boost::split and for loop: " << std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() << "us" << std::endl;
}
{
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
for (int i = 0; i < 1000000; ++i) {
std::vector<std::string> substrs;
folly::split(",", str, substrs);
for (const auto& substr : substrs) {
if (substr == pattern) {
std::string result = substr;
}
}
}
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
std::cout << "folly::split and for loop: " << std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() << "us" << std::endl;
}
// 字元串轉換
{
std::string str1 = "12345";
std::string str2 = "67890";
{
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
for (int i = 0; i < 1000000; ++i) {
std::string result = str1 + str2;
int value = std::stoi(result);
}
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
std::cout << "std::stoi: " << std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() << "us" << std::endl;
}
{
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
for (int i = 0; i < 1000000; ++i) {
std::string result = str1 + str2;
int value = boost::lexical_cast<int>(result);
}
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
std::cout << "boost::lexical_cast:

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/185964.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-11-26 21:08
下一篇 2024-11-26 21:08

相關推薦

  • Python字元串寬度不限制怎麼打代碼

    本文將為大家詳細介紹Python字元串寬度不限制時如何打代碼的幾個方面。 一、保持代碼風格的統一 在Python字元串寬度不限制的情況下,我們可以寫出很長很長的一行代碼。但是,為了…

    編程 2025-04-29
  • Python棧操作用法介紹

    如果你是一位Python開發工程師,那麼你必須掌握Python中的棧操作。在Python中,棧是一個容器,提供後進先出(LIFO)的原則。這篇文章將通過多個方面詳細地闡述Pytho…

    編程 2025-04-29
  • Python中將字元串轉化為浮點數

    本文將介紹在Python中將字元串轉化為浮點數的常用方法。在介紹方法之前,我們先來思考一下這個問題應該如何解決。 一、eval函數 在Python中,最簡單、最常用的將字元串轉化為…

    編程 2025-04-29
  • Java判斷字元串是否存在多個

    本文將從以下幾個方面詳細闡述如何使用Java判斷一個字元串中是否存在多個指定字元: 一、字元串遍歷 字元串是Java編程中非常重要的一種數據類型。要判斷字元串中是否存在多個指定字元…

    編程 2025-04-29
  • Python學習筆記:去除字元串最後一個字元的方法

    本文將從多個方面詳細闡述如何通過Python去除字元串最後一個字元,包括使用切片、pop()、刪除、替換等方法來實現。 一、字元串切片 在Python中,可以通過字元串切片的方式來…

    編程 2025-04-29
  • Python操作數組

    本文將從多個方面詳細介紹如何使用Python操作5個數組成的列表。 一、數組的定義 數組是一種用於存儲相同類型數據的數據結構。Python中的數組是通過列表來實現的,列表中可以存放…

    編程 2025-04-29
  • Python操作MySQL

    本文將從以下幾個方面對Python操作MySQL進行詳細闡述: 一、連接MySQL資料庫 在使用Python操作MySQL之前,我們需要先連接MySQL資料庫。在Python中,我…

    編程 2025-04-29
  • Python磁碟操作全方位解析

    本篇文章將從多個方面對Python磁碟操作進行詳細闡述,包括文件讀寫、文件夾創建、刪除、文件搜索與遍歷、文件重命名、移動、複製、文件許可權修改等常用操作。 一、文件讀寫操作 文件讀寫…

    編程 2025-04-29
  • Python代碼實現迴文數最少操作次數

    本文將介紹如何使用Python解決一道經典的迴文數問題:給定一個數n,按照一定規則對它進行若干次操作,使得n成為迴文數,求最少的操作次數。 一、問題分析 首先,我們需要了解迴文數的…

    編程 2025-04-29
  • Python元祖操作用法介紹

    本文將從多個方面對Python元祖的操作進行詳細闡述。包括:元祖定義及初始化、元祖遍歷、元祖切片、元祖合併及比較、元祖解包等內容。 一、元祖定義及初始化 元祖在Python中屬於序…

    編程 2025-04-29

發表回復

登錄後才能評論