排序算法:
// 冒泡 void sorta(int array[], int n) { for (int i = 0; i < n; i++) { for (int t = i + 1; t < n; t++) { if (array[i]>array[t]) { int space = array[i]; array[i] = array[t]; array[t] = space; } } } } // 选择 void sortb(int array[], int n) { for (int i = 0; i < n - 1; i++) { int k = i; // 内循环,查找i后面所有数中最小的一个的位置,放在k中 for (int j = i + 1; j<n; j++) { if (array[k] > array[j]) k = j; } // 如果k已经发生了变动,说明有更小的值,把它和i交换 if (k != i) { int space = array[i]; array[i] = array[k]; array[k] = space; } } } // 快速 void sortc(int arr[],int l,int r) { if (l < r) { int i = l, j = r, x = arr[l]; while (i < j) { while (i < j && arr[j] >= x) // 从右向左找第一个小于x的数 j--; if (i < j) // 如果找到更小的 arr[i++] = arr[j]; while (i < j && arr[i] < x) // 从左向右找第一个大于等于x的数 i++; if (i < j) arr[j--] = arr[i]; } arr[i] = x; sortc(arr, l, i - 1); // 递归调用,分而治之 sortc(arr, i + 1, r); } }
main函数:
#include "stdafx.h" #include "TestSonikk.h" #include "UTime.h" int _tmain(int argc, _TCHAR* argv[]) { TestSonikk ts; int n = 10000; std::string file_path = "F:\\test\\data.txt"; int* arr0 = nullptr; bool bRet = ts.readFileArray(file_path, arr0, n); // 从文件读取数组 if (bRet == false) { // 从外部读取失败,转从内部随机生成 arr0 = ts.makeRandomArray(n, 0, n); printf("内部生成数据ok. (n=%d) \r\n", n); // 如果没有从外部读取数据,则自动保存数据 ts.writeFileArray(file_path, arr0, n); printf("保存内部生成的数据到文件ok. (n=%d) \r\n", n); } else { printf("从外部文件读取数据ok. (n=%d) \r\n", n); } int* arr1 = ts.copyArray(arr0, n); int* arr2 = ts.copyArray(arr0, n); UTime ut; { ut.start(); sorta(arr0, n); printf("[冒泡] 所用时间: %s 秒\r\n", ut.end_str().c_str()); } { ut.start(); sortb(arr1, n); printf("[选择] 所用时间: %s 秒\r\n", ut.end_str().c_str()); } { ut.start(); sortc(arr2, 0, n - 1); printf("[快速] 所用时间: %s 秒\r\n", ut.end_str().c_str()); } // ts.printArray(arr0, n); // ts.printArray(arr1, n); // ts.printArray(arr2, n); system("pause"); return 0; }
Utime.h
#pragma once #include <stdio.h> #include "windows.h" // 精确的时间统计类 // @sonikk 2014-8-26 15:25:15 class UTime { public: UTime() { QueryPerformanceFrequency(&_freq); } void start() { QueryPerformanceCounter(&_start); } // @return s double end() { QueryPerformanceCounter(&_end); return (double)(_end.QuadPart - _start.QuadPart) / (double)_freq.QuadPart; } std::string end_str() { char buf[128]; double dt = end(); sprintf_s(buf, "%f", dt); return buf; } protected: LARGE_INTEGER _freq; LARGE_INTEGER _start; LARGE_INTEGER _end; };
TestSonikk.h
#pragma once #include <string> // 从文件读取、保存数组、数组的操作等的帮助类 // @sonikk 2014-8-26 15:25:15 class TestSonikk { public: int* makeRandomArray(int n, int min, int max); // 拷贝数组 int* copyArray(int* arr, int n); void printArray(int* arr, int n); // @n // @min // @max // @file_path std::string arrayToString(int* arr, int n); bool writeFile(std::string str, const std::string& file_path); std::string readFile(const std::string& file_path); // 截取str中的Int值 // @str 要截取的字符串 // @start 开始位置 // @end 结束位置 int takeInt(const std::string& str, int start, int end); // 从文件读取数据到数组 // @file_path // @n 数组长度 // @return 返回是否读取成功 bool readFileArray(const std::string& file_path, int*& arr_out, int n); // 将数组写入文件 bool writeFileArray(const std::string& file_path, int* arr, int n); protected: };
TestSonikk.cpp
#include "stdafx.h" #include <iostream> #include <fstream> #include <ctime> #include <string> #include "TestSonikk.h" #include "StringBuilder.h" int* TestSonikk::makeRandomArray(int n, int min, int max) { int* arr = new int[n]; srand(time(0)); for (int i = 0; i < n; ++i) { arr[i] = min + (rand() % (max - min + 1) ); } return arr; } int* TestSonikk::copyArray(int* arr, int n) { int* arr_copy = new int[n]; memcpy(arr_copy, arr, sizeof(int)*n); return arr_copy; } std::string TestSonikk::arrayToString(int* arr, int n) { StringBuilder<char> sb; //ansi.Append("Hello").Append(" ").AppendLine("World"); char buf[32]; for (int i = 0; i < n; ++i) { sprintf_s(buf, "%d", arr[i]); sb.Append(buf).Append(","); } return sb.ToString(); } void TestSonikk::printArray(int* arr, int n) { for (int i = 0; i < n; ++i) { printf("[%d]%d ", i, arr[i]); } printf("\r\n"); } bool TestSonikk::writeFile(std::string str, const std::string& file_path) { std::ofstream fs; //myfile.open(file_path); fs.open(file_path.c_str()); fs << str; fs.close(); return true; } std::string TestSonikk::readFile(const std::string& file_path) { std::string str = ""; std::fstream fs; fs.open(file_path.c_str()); fs >> str; fs.close(); // std::ifstream ifs; // std::stringstream buffer; // ifs.open(file_path.c_str()); // buffer << ifs.rdbuf(); // buffer.str(); // ifs.close(); return str; } int TestSonikk::takeInt(const std::string& str, int start, int end) { int val = 0; int carry = 1; for (int i = end; i >= start; --i) { val += (str[i] - '0') * carry; carry *= 10; } return val; } bool TestSonikk::readFileArray(const std::string& file_path, int*& arr_out, int n) { bool bRet = false; std::string str = readFile(file_path); if (str != "") { int* arr = new int[n]; memset(arr, 0, sizeof(int)*n); int count = 0; int start = 0; int end = -2; // *,123,45, *的位置为-2 char c; int strLen = str.length(); for (int i = 0; (i < strLen) && (count < n); ++i) { if (str[i] == ',') { start = end + 2; end = i - 1; arr[count++] = takeInt(str, start, end); } } arr_out = arr; bRet = true; } return bRet; } bool TestSonikk::writeFileArray(const std::string& file_path, int* arr, int n) { std::string str = arrayToString(arr, n); writeFile(str, file_path); return true; }
// Subset of http://msdn.microsoft.com/en-us/library/system.text.stringbuilder.aspx #include <iostream>// for std::cout, std::endl #include <string> // for std::string #include <list> #include <vector> // for std::vector #include <numeric> // for std::accumulate template <typename chr> class StringBuilder { typedef std::basic_string<chr> string_t; typedef std::list<string_t> container_t; // Reasons not to use vector below. typedef typename string_t::size_type size_type; // Reuse the size type in the string. container_t m_Data; size_type m_totalSize; void append(const string_t &src) { m_Data.push_back(src); m_totalSize += src.size(); } // No copy constructor, no assignement. StringBuilder(const StringBuilder &); StringBuilder & operator = (const StringBuilder &); public: StringBuilder(const string_t &src) { if (!src.empty()) { m_Data.push_back(src); } m_totalSize = src.size(); } StringBuilder() { m_totalSize = 0; } // TODO: Constructor that takes an array of strings. StringBuilder & Append(const string_t &src) { append(src); return *this; // allow chaining. } // This one lets you add any STL container to the string builder. template<class inputIterator> StringBuilder & Add(const inputIterator &first, const inputIterator &afterLast) { // std::for_each and a lambda look like overkill here. // <b>Not</b> using std::copy, since we want to update m_totalSize too. for (inputIterator f = first; f != afterLast; ++f) { append(*f); } return *this; // allow chaining. } StringBuilder & AppendLine(const string_t &src) { static chr lineFeed[] { 10, 0 }; // C++ 11. Feel the love! m_Data.push_back(src + lineFeed); m_totalSize += 1 + src.size(); return *this; // allow chaining. } StringBuilder & AppendLine() { static chr lineFeed[] { 10, 0 }; m_Data.push_back(lineFeed); ++m_totalSize; return *this; // allow chaining. } // TODO: AppendFormat implementation. Not relevant for the article. // Like C# StringBuilder.ToString() // Note the use of reserve() to avoid reallocations. string_t ToString() const { string_t result; // The whole point of the exercise! // If the container has a lot of strings, reallocation (each time the result grows) will take a serious toll, // both in performance and chances of failure. // I measured (in code I cannot publish) fractions of a second using 'reserve', and almost two minutes using +=. result.reserve(m_totalSize + 1); // result = std::accumulate(m_Data.begin(), m_Data.end(), result); // This would lose the advantage of 'reserve' for (auto iter = m_Data.begin(); iter != m_Data.end(); ++iter) { result += *iter; } return result; } // like javascript Array.join() string_t Join(const string_t &delim) const { if (delim.empty()) { return ToString(); } string_t result; if (m_Data.empty()) { return result; } // Hope we don't overflow the size type. size_type st = (delim.size() * (m_Data.size() - 1)) + m_totalSize + 1; result.reserve(st); // If you need reasons to love C++11, here is one. struct adder { string_t m_Joiner; adder(const string_t &s) : m_Joiner(s) { // This constructor is NOT empty. } // This functor runs under accumulate() without reallocations, if 'l' has reserved enough memory. string_t operator()(string_t &l, const string_t &r) { l += m_Joiner; l += r; return l; } } adr(delim); auto iter = m_Data.begin(); // Skip the delimiter before the first element in the container. result += *iter; return std::accumulate(++iter, m_Data.end(), result, adr); } }; // class StringBuilder
b