1. 程式人生 > >氣泡排序法、選擇排序法、快速排序法三者的效率對比,包括陣列的儲存與載入

氣泡排序法、選擇排序法、快速排序法三者的效率對比,包括陣列的儲存與載入

排序演算法:

// 冒泡
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