C++模板实现八大排序算法

C++模板实现八大排序算法

最近重新温习了一下十大排序算法,就用C++11模板试着实现了这些排序算法,各种数据类型都能操作,还可以像ST排序算法一般传入自定义排序规则,默认排序规则是less<>{},以下是所写程序:(其中桶排序和计数排序没有给出代码实现)

#pragma once
#include<utility>
/*所有函数调用格式:
sortMehtod(beginIterator, endIterator, compareMethod); 
最后的比较方法缺省为less<>{}
*/
/*对输入数据按特定规则分区,符合规则元素移到前面,返回符合规则的元素个数*/
template<typename Ite, class partitionCriterion  >//partitionCriterion:分区规则,对特定元素判断是否符合规则
inline size_t myPartition(Ite start, Ite final, partitionCriterion _pCriterion) {
	auto L = final - start;
	int k = 0;//记录当前符合规则的元素个数
	if (L) {
		for (auto i = 1; i < L; ++i) {//跳过初始元素
			if (_pCriterion(*(start + i))) {//满足入桶规则
				++k;
				std::swap(*(start + i), *(start + k));

			}
		}
		if (!_pCriterion(*(start))) {//保证最初start开始元素始终在区间开端
			std::swap(*(start), *(start + k));
		}
		else {
			++k;
		}
	}
	return k;
}


/*冒泡排序*/
template<typename Ite, class sortCriterion>
void bubbleSort(Ite start,Ite final, sortCriterion sCriterion ) {
	auto L= final - start;
	for (size_t LL = L; LL > 1;--LL) {
		bool issorted{ true };
		for (int i=0; i<LL-1; ++i) {
			if (sCriterion(*(start + i+1) , *(start + i )) ) {//大泡沫不断沉底
				std::swap(*(start + i), *(start +i+ 1));
				issorted = false;//若有序则退出排序
			}
		}
		if (issorted) {
			break;
		}
	}
}
template<typename Ite>
void bubbleSort(Ite start, Ite final) {
	bubbleSort(start, final, std::less<>{});
}
/*选择排序*/
template<typename Ite, class sortCriterion >
void selectionSort(Ite start, Ite final, sortCriterion sCriterion ) {
	auto L = final - start;
	for (int i = 0; i < L - 1; ++i) {
		auto minT = start + i;
		for (int j = i + 1; j < L; ++j) {
			if (sCriterion (*(start + j), *(minT))) {
				minT = start + j;//记录最小者
			}
		}
		if(minT!= start + i) std::swap(*(start + i), *minT);
	}
}
template<typename Ite>
void selectionSort(Ite start, Ite final) {
	selectionSort(start, final, std::less<>{});
}
/*插入排序*/
template<typename Ite, class sortCriterion  >
void insertionSort(Ite start, Ite final, sortCriterion sCriterion) {
	auto L = final - start;
	for (int i = 1; i < L ; ++i) {
		for (int j =i; j>0&& sCriterion(* (start + j) , *(start + j - 1)); --j) {
			std::swap(*(start + j) , *(start + j - 1));//一直向前交换直到前一个元素已经不大于当前元素
		}
	}
}
template<typename Ite>
void insertionSort(Ite start, Ite final) {
	insertionSort(start, final, std::less<>{});
}
/*归并排序*/
template<typename Ite, class sortCriterion  >
void merge(Ite start1, Ite start2, Ite final2, sortCriterion sCriterion) {
	for (; start2 != final2; ++start2) {
		for (auto temp = start2; temp > start1 &&sCriterion(*(temp), *(temp -1));--temp) {//一直向前交换直到前一个元素已经不大于当前元素,思路类似于插入排序
			std::swap(*(temp), *(temp - 1));
		}	
	}
}
template<typename Ite, class sortCriterion  >
void mergeSort(Ite start, Ite final, sortCriterion sCriterion) {
	auto L = final - start;
	if (L > 1) {
		mergeSort(start, start + L / 2, sCriterion);//假设调用函数后前后两个区域已经各自有序
		mergeSort(start + L / 2, final, sCriterion);
		merge(start,start + L / 2, final,sCriterion);//合并两个有序区域
	}
}
template<typename Ite>
void mergeSort(Ite start, Ite final) {
	mergeSort(start, final, std::less<>{});
}
/*快速排序*/
template<typename Ite, class sortCriterion  >
void quickSort(Ite start, Ite final, sortCriterion sCriterion) {
	if (start!=final) {
		size_t num = myPartition(start, final, [&start,&sCriterion](auto ele) ->bool {
			return sCriterion(ele,*(start));
			});
		quickSort(start, start + num, sCriterion);//对不同分区分别排序
		quickSort(start + num+1, final, sCriterion);
	}
}
template<typename Ite>
void quickSort(Ite start, Ite final) {
	quickSort(start, final, std::less<>{});
}
/*堆排序*/
template<typename Ite, class sortCriterion  >
void heapSort(Ite start, Ite final, sortCriterion sCriterion) {
	for (auto L = final - start; L > 1; --L) {
		for (auto i = L; i > 1; --i) {//从叶子节点向根节点开始遍历
			if (sCriterion(*(start + i / 2 - 1), *(start + i - 1))) {//如果子节点大于父节点则交换
				std::swap(*(start + i / 2 - 1), *(start + i - 1));
			}//构建最大堆
		}
		std::swap(*(start), *(start + L - 1));//将根节点与最后的叶子节点交换
	}
}
template<typename Ite>
void heapSort(Ite start, Ite final) {
	heapSort(start, final, std::less<>{});
}

/*希尔排序(对增量区间(间隔划分区间)进行插入排序)*/
template<typename Ite, class sortCriterion  >
void shellSort(Ite start, Ite final, sortCriterion sCriterion) {
	auto L = final - start;
	for (auto delta = L / 2; delta >= 1; delta /= 2) {
		//插入排序对应与delta为1;
		for (auto i = delta; i < L; ++i) {//i = delta表示第一个区间的第二个元素,通过i的递增,保证了各个区间除区间起点以外都被遍历到
			for (auto j = i; j >= delta && sCriterion(*(start + j), *(start + j - delta)); j -= delta) {//从i开始向前遍历i所在区间,对该区间插入排序
				std::swap(*(start + j - delta), *(start + j));
			}
		}
	}
}
template<typename Ite>
void shellSort(Ite start, Ite final) {
	shellSort(start, final, std::less<>{});
}

/*桶排序*/
//此处桶可理解为:符合某准规则的元素集合,多个桶表示有多种规则,需保证待排序元素为所有桶并集的子集
template<typename Ite, class sortCriterion  >
void BucketSort(Ite start, Ite final, sortCriterion sCriterion) {
	;
}
template<typename Ite>
void BucketSort(Ite start, Ite final) {
	BucketSort(start, final, std::less<>{});
}

/*基数排序*/
//特殊的桶排序
template<typename Ite, class sortCriterion>
void RadixSorter(Ite start, Ite final, sortCriterion sCriterion) {
	auto L = final - start;
	size_t numRadix[10]{};//用于记录每个桶的元素个数
	for (int k = 1; numRadix[0] < L; ++k) {
		for (int i = 0; i < 10;++i) {//按每一位填入桶
			auto pCrite = [&i, &k](const auto& ele) ->bool {//i表示不同桶,k表示个位(1)、十位(2)、百位(3)...
				auto temp{ ele };
				auto k_{ k };
				while ((--k_) && (temp /= 10));
				return temp % 10 == i;
			};//判断元素ele是否入桶
			auto accuNum = i == 0 ? 0 : numRadix[i - 1];
			numRadix[i] = myPartition(start + accuNum, final, pCrite) + accuNum;//记录当前入桶元素

			//保证桶内元素有序,在基本有序情况下插入排序性能较高(本来基数排序不需要对桶内部排序,但是由于上面调用的分区算法不稳定,所以需要再排列)
			shellSort(start + accuNum, final, sCriterion);
			if (numRadix[i]>=L) {
				break;
			}
		}
	}
}
template<typename Ite>
void RadixSorter(Ite start, Ite final) {
	RadixSorter(start, final, std::less<>{});
}

以下是主函数性能测试代码:

int main(int argc, char* argv[])
{ 
    clock_t average{};
    for (int j = 0; j < 100; ++j) {
        srand((unsigned int)time(nullptr));
        vector<int> nums{};
        for (int i = 0; i < 1000; ++i) {
            nums.push_back(rand());
        }
        clock_t start, finish;
        start = clock();
        RadixSorter(nums.begin(), nums.end());
        finish = clock();
        if (!is_sorted(nums.begin(), nums.end())) {
            cout << "算法测试不成功" << endl;
        }
        average = (average * j + finish - start) / (j + 1);
    }
    cout<<"算法测试成功,平均时间为:"<< average;
    return 0;
}

算法性能验证

最后各个排序算法在1000的数据量下的平均耗时为(重复100次):
选择:122
冒泡:512
插入:336
归并:139
快速:6
堆排序:621
希尔:14
基数:312
(基数排序之所以这么大有可能是因为我在每个桶内排序的原因)

最后问题:

有时候一些递归算法会爆栈。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值