排序算法:
// 冒泡
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 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
#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
// 从文件读取、保存数组、数组的操作等的帮助类
// @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
#include
#include
#include
#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 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 // for std::cout, std::endl
#include // for std::string
#include
#include // for std::vector
#include // for std::accumulate
template
class StringBuilder
{
typedef std::basic_string string_t;
typedef std::list 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
StringBuilder & Add(const inputIterator &first, const inputIterator &afterLast) {
// std::for_each and a lambda look like overkill here.
// Not 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