排序算法

环境: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


Sort.cpp

#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;
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值