氣泡排序法、選擇排序法、快速排序法三者的效率對比,包括陣列的儲存與載入
阿新 • • 發佈:2019-01-01
排序演算法:
// 冒泡 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;
}
StringBuilder.h
// 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