环境:VS2008
Sort.h
/***
* Sort.h - 各种排序算法
*
* Author:Michael 2012-09-12
*
****/
#ifndef SORT_H
#define SORT_H
class Sort{
public:
//插入排序
void InsertSort(int a[], int n); //直接插入排序
void ShellSort(int a[], int na, int delta[], int nd);//希尔排序
//交换排序
void BubbleSort(int a[], int n);//冒泡排序
void QuickSort(int a[], int low, int high);//快速排序
//选择排序
void SelectSort(int a[], int n);//简单选择排序
void HeapSort(int a[], int n);//堆排序
//归并排序
void MergeSort(int a[], int s, int t);
private:
void ShellInsert(int a[], int na, int dk);//一趟希尔排序
int Partition(int a[], int low, int high);//一趟快速排序
void HeapAdjust(int a[], int s, int m);//堆调整
//归并操作,将有序子列a[being,..,mid]以及a[mid + 1,..,end]进行归并
void Merge(int a[], int begin, int mid, int end);
};
#endif
#include "Sort.h"
/**
*直接插入排序,从第二个数开始,把前面的序列看作有序的,后面的元素只需要找到在
*前面有序列中需要插入的位置即可。
*时间复杂度:O(n²),空间复杂度O(1),只需要一个辅助记录的空间
*/
void Sort::InsertSort(int a[], int n){
for(int i = 1; i < n; i++){
int temp = a[i];
int k = i - 1;
for(; k >= 0; k--){
if(a[k] > temp)
a[k + 1] = a[k];
else
break;//注意跳出,这个时候,已经找到需要插入的位置了
}
a[k + 1] = temp;
}
}
/**
*一趟希尔排序
*把原数组按照增量dk划分,相当于对每一个子数组都进行直接插入排序
*/
void Sort::ShellInsert(int a[], int na, int dk){
//注意外层循环i和内层循环j的值如何变化
for(int i = dk; i < na; i++){//外层循环保证遍历整个数组
int temp = a[i];
int j = i - dk;
for(; j >= 0; j -= dk){//内层循环对增量为dk的子数组进行直接插入排序
if(a[j] > temp)
a[j + dk] = a[j];//j + dk而不是直接插入排序中的j + 1
else
break;
}
a[j + dk] = temp;
}
}
/**
*希尔排序
*希尔排序的思想是先把整个数组进行排序,让其大致有序,然后进行排序
*增量数组delta的最后一个元素必须为1,所以最后一趟为直接插入排序。但是由于
*数组已经基本有序了,所以最后一趟的比较和移动次数不多
*时间复杂度为O(n3/2)
*/
void Sort::ShellSort(int a[], int na, int delta[], int nd){
for(int i = 0; i < nd; i++){
ShellInsert(a, na, delta[i]);
}
}
/**
*冒泡排序
*时间复杂度为O(n²)
*/
void Sort::BubbleSort(int a[], int n){
for(int i = 0; i < n - 1; i++){
bool ifMoved = false;
for(int j = n - 1; j > i ; j--){//较小的往前
if(a[j] < a[j - 1]){
int temp = a[j];
a[j] = a[j - 1];
a[j - 1] = temp;
ifMoved = true;
}
}
//如果在一趟排序的过程中没有交换记录,说明整个数组有序,结束
if(ifMoved == false)
break;
}
}
/**
*一趟快排
*以a[low]为枢轴,从后面找到第一个比a[low]小的然后把值赋给a[low],
*从前面找第一个比a[low]大的然后把值赋给a[high]
*这样,在low之前的值都比pivot小,在high之后的值都比pivot大
*当low==high的时候,就把数组一分为二了
*/
int Sort::Partition(int a[], int low, int high){
int pivot = a[low];
while(low < high){
while(a[high] >= pivot && low < high)
high--;
a[low] = a[high];
while(a[low] <= pivot && low < high)
low++;
a[high] = a[low];
}
a[low] = pivot;
return low;
}
/*
*快速排序
*在所有同数量级(O(nlogn))的排序方法中,性能最好
*但是若初始记录基本有序是,快排蜕化为冒泡复杂度为O(n²)
*/
void Sort::QuickSort(int a[], int low, int high){
if(low < high){
int position = Partition(a, low, high);
QuickSort(a, low, position - 1);
QuickSort(a, position + 1, high);
}
}
/**
*选择排序
*外层循环只用进行n-1次,因为n-1次就能select n-1个比较小的
*那么最后一个一定是最大的
*时间复杂度为O(n²)
*/
void Sort::SelectSort(int a[], int n){
for(int i = 0; i < n - 1; i++){
int min = a[i];
int index = i;
int j;
for(j = i + 1; j < n; j++){
if(min > a[j]){
min = a[j];
index = j;//记录最小值所在的数组下标
}
}
if(i == index) continue;
//swap a[i] and a[index]
int temp = a[i];
a[i] = a[index];
a[index] = temp;
}
}
void Sort::Merge(int a[], int begin, int mid, int end){
int* dData = new int[end - begin + 1];
int i,j,k;
for(i = begin,j = mid + 1,k = 0;i <= mid && j <= end;)
{
if(a[i] <= a[j])
{
dData[k] = a[i];
i++;
}
else
{//i和j位置的值交换,并且i+1,在原串上进行归并不可行
dData[k] = a[j];
/*交换会破坏原来两个子串的有序结构,所以不可行*/
/*temp = a[i];
a[i] = a[j];
a[j] = temp;
i++;*/
j++;
}
k = k + 1;
}
while(i <= mid)
{
dData[k] = a[i];
k++;
i++;
}
while(j <= end)
{
dData[k] = a[j];
k++;
j++;
}
for(k = 0,i = begin;i <= end;k++,i++)
a[i] = dData[k];
//free dData
delete[] dData;
}
/**
*归并排序
*时间复杂度O(nlogn)
*/
void Sort::MergeSort(int a[], int s, int t){
int m;
if(s < t){
m = (s + t) / 2;
MergeSort(a, s, m);
MergeSort(a, m + 1, t);
Merge(a, s, m, t);
}
}
/**
*堆调整
*堆调整的过程是自下向上进行的,当进行到s处的时候,s的左右孩子
*已经是堆了
*/
void Sort::HeapAdjust(int a[], int s, int m){
while(2 * s + 1 < m){//注意m应该是数组元素个数
int MaxChildIndex = 2 * s + 1;
if(MaxChildIndex + 1 < m){
//找到较大孩子的下标
if(a[MaxChildIndex + 1] > a[MaxChildIndex])
MaxChildIndex += 1;
}
if(a[MaxChildIndex] > a[s]){//s处的值比孩子的值小,需要调整
int temp = a[s];
a[s] = a[MaxChildIndex];
a[MaxChildIndex] = temp;
//MaxChildIndex子堆被破坏,需要调整
s = MaxChildIndex;
}
else//s处的值比孩子的值都大,而孩子又满足堆结构,所以循环结束
break;
}
}
void Sort::HeapSort(int a[], int n){
//建堆,建堆就是一个不断堆调整的过程,从最后一个非叶子节点开始自底向上
for(int i = n / 2 - 1; i >= 0; i--)
HeapAdjust(a, i, n);
//完成之后a是一个大顶堆
for(int i = n - 1; i > 0; i--){
//把堆顶元素与a[i]进行交换,那么a[i]中放的就是堆中的最大值
int temp = a[0];
a[0] = a[i];
a[i] = temp;
//接下来,调整堆
HeapAdjust(a, 0, i);
}
}
main.cpp
#include <iostream>
#include <string.h>
#include "Sort.h"
using namespace std;
int main()
{
int a[9] = {4,2,45,12,75,54,63,84,30};
int delta[3] = {3, 2, 1};
Sort sort;
int len = sizeof(a) / sizeof(int);
/*test the functions*/
//sort.InsertSort(a, len);
//sort.ShellSort(a, len, delta, 3);
//sort.QuickSort(a, 0, len - 1);
//sort.SelectSort(a, len);
//sort.BubbleSort(a, len);
//sort.MergeSort(a, 0, len - 1);
sort.HeapSort(a, len);
for(int i = 0; i < len; i++)
cout << a[i] << " ";
system("pause");
return 0;
}