题目需求:
算法:
/// 字符串循环左移或右移N个字符的算法 /// * 将整个串全反转 /// * 按照需要移动的字符个数将反转后的串分为2部分 /// * 将这2个子字符串分别进行反转 /// /// e.g. 原串: hello world, 要求循环左移3个字符 /// * 将整个串反转, dlrow olleh /// * 按照循环的字符数3, 将翻转后的串分为2部分, [dlrow ol][leh] /// * 将这2个子字符串分别进行反转 [lo world][hel] /// 得到字符串按照字符为单位循环移位的结果为 lo worldhel
测试程序算法实现:
// srcStringCirculator.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <windows.h> #include <locale.h> #include <tchar.h> #include "Helper\StringHelper.h" /// 字符串循环左移或右移N个字符的算法 /// * 将整个串全反转 /// * 按照需要移动的字符个数将反转后的串分为2部分 /// * 将这2个子字符串分别进行反转 /// /// e.g. 原串: hello world, 要求循环左移3个字符 /// * 将整个串反转, dlrow olleh /// * 按照循环的字符数3, 将翻转后的串分为2部分, [dlrow ol][leh] /// * 将这2个子字符串分别进行反转 [lo world][hel] /// 得到字符串按照字符为单位循环移位的结果为 lo worldhel void DoStringCirculatorOnce(); ///< 开始一次字符串字符移位 bool IsDoStringCirculatorAgain(); ///< 是否再开始一次新的字符串字符移位 int _tmain(int argc, _TCHAR* argv[]) { setlocale(LC_CTYPE, ".936"); //< 控制台为中文输出 do { DoStringCirculatorOnce(); } while (IsDoStringCirculatorAgain()); _tprintf(L"\r\nEND, press any key to quit\r\n"); getchar(); /** run results */ return 0; } void DoStringCirculatorOnce() { wchar_t szBuf[_MAX_PATH]; ///< 用户输入的原始字符串 wchar_t * pszBuf = &szBuf[0]; size_t nInputBufLenMax = SIZEOF_WCHAR_ARRAY(szBuf); bool bLoopLeft = true; size_t nLoopCnt = 0; if (!GetUserInputStringCirculatorParam(pszBuf, nInputBufLenMax, bLoopLeft,nLoopCnt)) return; if (StringCirculator(pszBuf, bLoopLeft,nLoopCnt)) _tprintf(L"\r\n循环字符移位后的串为 : [%s]\n", szBuf); else _tprintf(L"\r\n操作失败\r\n"); } bool IsDoStringCirculatorAgain() { bool bRc = true; wchar_t cInput = L' '; ///< 用户输入的单个字符 wchar_t * pcInput = NULL; wchar_t szloopCnt[_MAX_PATH]; ///< 容纳用户输入的移位字符数 wchar_t * pszloopCnt = NULL; _tprintf(L"\r\n是否开始一次新的字符串字符移位? 输入'Y'为继续, 输入'N'为取消, 支持大小写\r\n"); pcInput = &cInput; GetUsrInput(pcInput, SIZEOF_WCHAR_ARRAY(cInput)); bRc = ((L'Y' == cInput) || (L'y' == cInput)); _tprintf(L"\r\n\r\n您的选择为[%s]\r\n", bRc ? L"继续" : L"取消"); return bRc; }
/// @file helper\StringHelper.h /// @brief 字符串辅助操作定义 #ifndef __HELPER_STRING_HELPER_H__ #define __HELPER_STRING_HELPER_H__ #include <windows.h> #include <locale.h> #include <tchar.h> #define WCHAR_STR_END L'\0' ///< 串结束符 #define WCHAR_WORD_END L' ' ///< 单词结束符 #define SIZEOF_WCHAR_ARRAY(x) (sizeof((x)) / sizeof(wchar_t)) /// @fn ReverseStringByWord /// @brief 对入参串进行单词反转, 单词之间的分隔符号为空格, /// e.g. Hello world, driver => driver world Hello /// @param IN OUT wchar_t * pcMsgW, 输入输出串, 反转后的结果串覆盖原字符串 /// @return bool /// @retval true, 串反转成功 /// @retval false, 串反转失败 bool ReverseStringByWord(IN OUT wchar_t * pcMsgW); /// @fn ReverseString /// @brief 对入参串进行完全反转 /// e.g. 123456 7890 => 0987 654321 /// @param IN OUT wchar_t * pcMsgW, 输入输出串, 反转后的结果串覆盖原字符串 /// @param IN size_t nLenMsg, 串长度 /// @return bool /// @retval true, 串反转成功 /// @retval false, 串反转失败 bool ReverseString(IN OUT wchar_t * pcMsgW, IN size_t nLenMsg); /// @fn GetStringLength /// @brief 此算法不允许用C库函数参与串长度计算, 模拟实现计算串长度 /// @param IN const wchar_t * pcMsgW, 输入串 /// @param IN const wchar_t & cEndSeparator, 串的结束分隔符 /// @param IN const wchar_t & cStrEndSeparator, 字符串结尾字符 /// @return size_t, 返回的串长度. 如果串为NULL, 返回0. size_t GetStringLength(IN const wchar_t * pcMsgW, IN const wchar_t & cEndSeparator, IN const wchar_t & cStrEndSeparator = WCHAR_STR_END); /// @fn GetUserInputStringCirculatorParam /// @brief 请用户输入字符串, 指定左移或右移, 移位的字符数 /// @param wchar_t *& pszUsrInput, 容纳用户输入字符的缓冲区, 外部给定, 必须有效 /// @param size_t nInputBufLenMax, 输入缓冲区最大容量 /// @param bool & bLoopLeft, 左移 = TRUE, 右移 = FALSE /// @param size_t & nLoopCnt, 移位的字符数, 可以大于字符串长度, 也可以为零, /// 最后的移位字符数为字符串实际长度(不包括结尾'\0')的模 /// @return bool /// @retval true, 用户输入参数成功 /// @retval false, 用户输入参数失败 bool GetUserInputStringCirculatorParam(wchar_t *& pszUsrInput, size_t nInputBufLenMax, bool & bLoopLeft, size_t & nLoopCnt); /// @fn GetUsrInput /// @brief 给定输入缓冲区, 等待用户输入, 以回车作为结束符 /// @param wchar_t *& pszUsrInput, 输入缓冲区 /// @param size_t nInputBufLenMax, 输入缓冲区长度 /// @return void void GetUsrInput(wchar_t *& pszUsrInput, size_t nInputBufLenMax); /// @fn StringCirculator /// @brief 对输入串进行按字符数循环移位 /// @param wchar_t *& pszUsrInput, 输入串 /// @param bool bLoopLeft, 左移 = TRUE, 右移 = FALSE /// @param size_t nLoopCnt, 移位的字符数, 可以大于字符串长度, 也可以为零, /// 最后的移位字符数为字符串实际长度(不包括结尾'\0')的模 /// @return bool /// @retval true, 成功 /// @retval false, 失败 bool StringCirculator(wchar_t *& pszUsrInput, bool bLoopLeft, size_t nLoopCnt); #endif
/// @file helper\StringHelper.cpp /// @brief 字符串辅助操作, 实现串反转, 字符串移位等操作 #include "stdafx.h" #include "StringHelper.h" bool ReverseStringByWord(wchar_t * pcMsgW) { size_t nLenAll = 0; size_t nPosNow = 0; size_t nPosPrev = 0; size_t nLenStr = 0; if (NULL == pcMsgW) return false; /// 反转整个串 nLenAll = GetStringLength(pcMsgW, WCHAR_STR_END); if (!ReverseString(pcMsgW, nLenAll)) return false; /// 反转每个单词 while (nPosPrev < (nLenAll - 1)) { nLenStr = GetStringLength(pcMsgW + nPosPrev, WCHAR_WORD_END); /// 串长度 - 1 是位置, 位置是基于0的 nPosNow = nPosPrev + nLenStr - 1; if ((nPosNow <= nPosPrev) || (!ReverseString(pcMsgW + nPosPrev, nLenStr))) break; /// 下一个单词的起点是上一个单词的起点 + 一个单词分隔符长度 + 下一个单词的首字符 nPosPrev = nPosNow + 2; } return true; } bool ReverseString(IN OUT wchar_t * pcMsgW, IN size_t nLenMsg) { wchar_t * pcBegin = NULL; wchar_t * pcEnd = NULL; if (NULL == pcMsgW) return false; if (nLenMsg <= 1) return true; pcBegin = pcMsgW; pcEnd = pcMsgW + nLenMsg - 1; while (pcBegin < pcEnd) { /// 交换字符 *pcBegin ^= *pcEnd; *pcEnd ^= *pcBegin; *pcBegin ^= *pcEnd; /// 移动头尾指针 pcBegin++; pcEnd--; } return true; } size_t GetStringLength(IN const wchar_t * pcMsgW, IN const wchar_t & cEndSeparator, IN const wchar_t & cStrEndSeparator) { size_t nLenCnt = 0; const wchar_t * pcBegin = pcMsgW; if (NULL == pcBegin) return 0; while ((*(pcBegin + nLenCnt) != cEndSeparator) && (*(pcBegin + nLenCnt) != cStrEndSeparator)) nLenCnt++; ///< 当前字符不是cEndSeparator, 也不是字符串结尾, 计数++ return nLenCnt; } bool GetUserInputStringCirculatorParam(wchar_t *& pszUsrInput, size_t nInputBufLenMax, bool & bLoopLeft, size_t & nLoopCnt) { wchar_t cInput = L' '; ///< 用户输入的单个字符 wchar_t * pcInput = NULL; wchar_t szloopCnt[_MAX_PATH]; ///< 容纳用户输入的移位字符数 wchar_t * pszloopCnt = NULL; if (nInputBufLenMax < 1) { _tprintf(L"缓冲区长度无效, 必须 >= 1\r\n"); return false; } if (NULL == pszUsrInput) { _tprintf(L"缓冲区为空\r\n"); return false; } _tprintf(L"\r\n请输入字符串, 支持中文和分隔符, 以回车作为输入结束符:\r\n"); ::ZeroMemory(pszUsrInput, nInputBufLenMax * sizeof(wchar_t)); GetUsrInput(pszUsrInput, nInputBufLenMax); _tprintf(L"\r\n该字符串是左移还是右移? 输入'L'为左移, 输入'R'为右移, 支持大小写\r\n"); pcInput = &cInput; GetUsrInput(pcInput, SIZEOF_WCHAR_ARRAY(cInput)); bLoopLeft = ((L'L' == cInput) || (L'l' == cInput)); _tprintf(L"\r\n请输入移位字符数, 可以为0 或大于字符串长度, 最终的移位字符数为您输入的移位字符数模字符串长度\r\n"); ::ZeroMemory(szloopCnt, sizeof(szloopCnt)); pszloopCnt = &szloopCnt[0]; GetUsrInput(pszloopCnt, SIZEOF_WCHAR_ARRAY(szloopCnt)); nLoopCnt = _ttoi64(szloopCnt); _tprintf(L"\r\n\r\n您输入的字符串为: [%s]\r\n", pszUsrInput); _tprintf(L"\r\n字符串循环字符移位操作为: %s%d个字符\r\n", bLoopLeft ? L"左移" : L"右移", nLoopCnt); } void GetUsrInput(wchar_t *& pszUsrInput, size_t nInputBufLenMax) { size_t nPos = 0; wchar_t cInput = L' '; if ((NULL == pszUsrInput) || (nInputBufLenMax < 1)) return; while(1) { cInput = getwchar(); ///< _tprintf_s 有问题,不支持','分隔, 采用getwchar循环接收代替 if (L'\n' == cInput) break; if (nPos >= nInputBufLenMax) break; *(pszUsrInput + nPos++) = cInput; } } bool StringCirculator(wchar_t *& pszUsrInput, bool bLoopLeft, size_t nLoopCnt) { size_t nLenAll = 0; size_t nLoopCntReal = 0; if (NULL == pszUsrInput) return false; /// 反转整个串 nLenAll = GetStringLength(pszUsrInput, WCHAR_STR_END); if (!ReverseString(pszUsrInput, nLenAll)) return false; if (nLenAll < 1) return false; nLoopCntReal = nLoopCnt % nLenAll; if (0 == nLoopCntReal) return true; /// 反转2个子串, 串边界为 nLenAll - nLoopCntReal ReverseString(pszUsrInput, bLoopLeft ? (nLenAll - nLoopCntReal) : nLoopCntReal); ReverseString( pszUsrInput + (bLoopLeft ? (nLenAll - nLoopCntReal) : nLoopCntReal), bLoopLeft ? nLoopCntReal : (nLenAll - nLoopCntReal)); return true; }