#include "stdafx.h"
#include "iostream"
using namespace std;
// 排序算法大总结
// 共用函数声明
void output_array(int data[], int n);
void exchange(int *a, int *b);
//
// 插入
// 核心思想:把后面的元素插入到前面已经排好的数组中;所谓插入,向前比大小,若比该元素大,后移,直到找到它该去的位置
// 时间复杂度O(N^2);空间复杂度O(1);不稳定
void InsertSort(int *data, int len)
{
for (int i=1; i<len; i++)
{
int key = data[i];
int j = i -1;
while(key<data[j])
{
data[j+1] = data[j];
j--;
}
data[j+1] = key;
}
}
// 希尔:插入的一种
// http://www.cnblogs.com/nokiaguy/archive/2008/05/16/1199359.html
/* 先取一个正整数d1<n,把所有序号相隔d1的数组元素放一组,组内进行直接插入排序;
然后取d2<d1,重复上述分组和排序操作;直至di=1,即所有记录放进一个组中排序为止*/
/*
假设待排序文件有个记录,其关键字分别是:
49,,,,,,,,,。
增量序列的取值依次为: ,,
初始:d=5 38 65 97 76 13 27 49* 55 04
49 13 |-------------------|
38 27 |-------------------|
65 49* |-------------------|
97 55 |-------------------|
76 04 |-------------------|
一趟结果 27 49* 55 04 49 38 65 97 76
d=3 27 49* 55 04 49 38 65 97 76
13 55 38 76 |------------|------------|------------|
27 04 65 |------------|------------|
49* 49 97 |------------|------------|
二趟结果 04 49* 38 27 49 55 65 97 76
d=1 04 49* 38 27 49 55 65 97 76
|----|----|----|----|----|----|----|----|----|
三趟结果 13 27 38 49* 49 55 65 76 97
*/
// 时间复杂度O(N^2);空间复杂度O(1);不稳定
void ShellSortSub(int data[], int n, int increment) //data表示某分组的起始元素
{
for(int i=increment; i < n; i += increment) // i表示该组的元素数目
{
for(int j=i; j >= increment && data[j] < data[j - increment]; j -= increment)
{
exchange(&data[j], &data[j - increment]);
}
}
}
void ShellSort(int *data, int len)
{
for(int i=len/2; i>2; i/=2) // 增量规则;len/2,也可以是其他的
{
for(int j=0; j<i; j++) //分组的数目
{
ShellSortSub(data + j, len - j, i);
}
}
ShellSortSub(data, len, 1);
}
//
// 选择
// 核心思想:从某位置向右找,找到最小的元素,将二者位置交换;即一次次选最小,直到排序排好
// 时间复杂度O(N^2);空间复杂度O(1);不稳定
int FindMin(int *data, int begin, int end); //子函数
void SelectSort(int *data, int len)
{
for (int i=0; i<len; i++)
{
int k = FindMin(data, i, len-1);
if (k!=i)
{
exchange(data+k, data+i);
}
}
}
int FindMin(int *data, int begin, int end)
{
int min = data[begin];
int index = begin;
for (int i=begin+1; i<=end; i++)
{
if (data[i]<min)
{
min = data[i];
index = i;
}
}
return index;
}
//
// 合并
// 核心思想:利用归并的思想,将数组对半分,再分,直到每个小数组中只有一个元素;再合并,合并时,判断大小,像扑克牌一样,(*^__^*) ……
// 时间复杂度O(N*logN);空间复杂度O(N)___?;稳定
void Merge(int *data, int p, int q, int r); // SubFunction
void MergeSort(int *data, int p, int r) //p:起始位置,r:结束位置
{
if (p<r)
{
int q = (p + r)/2;
MergeSort(data, p, q);
MergeSort(data, q+1, r);
Merge(data, p, q, r); // 合并
}
}
void Merge(int *data, int p, int q, int r)
{
int n1 = q-p+1;
int n2 = r-q;
int *Left = new int[n1];
int *Right = new int[n2];
for (int i=p; i<=q; i++)
{
Left[i-p] = data[i];
}
for (int i=q+1; i<=r; i++)
{
Right[i-q-1] = data[i];
}
// 就像两沓子已经排好序扑克牌,对其进行合并排序
int p1=0; //标记Left
int p2=0; //标记Right
int index = 0; //标记原数组
for (index=p; index<=r && p1<n1 && p2<n2; index++)
{
if (Left[p1] <= Right[p2])
{
data[index] = Left[p1];
p1++;
}
else
{
data[index] = Right[p2];
p2++;
}
}
// Left 或Right仍有剩余
while(p1<n1)
{
data[index++] = Left[p1++];
}
while(p2<n2)
{
data[index++] = Right[p2++];
}
delete []Left;
delete []Right;
}
//
// 冒泡
// 核心思想:把数组看成气泡,只能轻的在重的智商
// 时间复杂度O(N^2);空间复杂度O(1);不稳定
void BubbleSort(int *data, int len)
{
for (int i=0; i<len; i++)
{
for (int j=len-1; j>i; j--)
{
if (data[j]<data[j-1])
{
exchange(data+j, data+j-1);
}
}
}
}
//
// 堆排序
// 核心思想:建最大堆,取根元素,放在数组末尾(将原尾元素与根元素交换),然后重建堆
// 时间复杂度O(N*logN);空间复杂度O(1);不稳定
int left(int i);
int right(int i);
int parent(int i);
void MaxHeapify(int *data, int len, int i);
void BuildMaxHeap(int *data, int len);
void HeapSort(int *data, int len)
{
BuildMaxHeap(data, len);
for (int i=len-1; i>=0; i--)
{
exchange(data, data+i);
len--;
MaxHeapify(data, len, 0);
}
}
void BuildMaxHeap(int *data, int len)
{
for (int i=len/2-1; i>=0; i--)
{
MaxHeapify(data, len, i);
}
}
void MaxHeapify(int *data, int len, int i) // 关键函数:建立以i为根的最大堆
{
int L = left(i);
int R = right(i);
int largest = 0;
if (L<len && data[L]>data[i])
{
largest = L;
}
else
{
largest = i;
}
if (R<len && data[R]>data[largest])
{
largest = R;
}
if (largest!=i)
{
exchange(data+i, data+largest);
MaxHeapify(data, len, largest);
}
}
int left(int i)
{
return 2*i;
}
int right(int i)
{
return 2*i+1;
}
int parent(int i)
{
return i/2;
}
//
// 快排(两种)
// 核心思想:将末尾的元素放在它该放的位置——靠两个指针实现。使它之前的元素小于它,之后的大于它。子数组重复
// 时间复杂度O(N*logN);空间复杂度O(1);不稳定
int Partition(int *data, int p, int r);
void QuickSort(int *data, int p, int r)// p:起始位置r:末尾位置
{
if (p<r)
{
int q = Partition(data, p, r); // 核心函数
QuickSort(data, p, q-1);
QuickSort(data, q+1, r);
}
}
int Partition(int *data, int p, int r)
{
int key = data[r];
int i=p-1; // 第一个标记:存放小于key的元素的末位置
for (int j=p; j<r; j++)
{
if (data[j]<=key)
{
i++;
exchange(data+i, data+j);
}
}
exchange(data+i+1, data+r);
return i+1;
}
/*
还有一种想法是这样的:
1)设置两个变量I、J,排序开始的时候:I=0,J=N-1;
2)以第一个数组元素作为关键数据,赋值给key,即key=A[0];
3)从J开始向前搜索,即由后开始向前搜索(J=J-1),找到第一个小于key的值A[J],并与key交换;
4)从I开始向后搜索,即由前开始向后搜索(I=I+1),找到第一个大于key的A[I],与key交换;
5)重复第、、步,直到I=J;(3,4步是在程序中没找到时候j=j-1,i=i+1,直至找到为止。
找到并交换的时候i,j指针位置不变。另外当i=j这过程一定正好是i+或j-完成的最后另循环结束。)
*/
//
// 计数排序
/* 对元素有限定条件:所有元素都小于K
用K大的数组标记每个元素出现的次数,再累加;
对数组进行重置,即已经知道有多少个元素在它前面
*/
// 时间复杂度O(N);空间复杂度O(len*K);稳定
void CountingSort(int *data, int len, int K)
{
int *newData = new int[len];
int *C = new int[K];
memset(C, 0, sizeof(int)*(K+1));
for (int i=0; i<len; i++)
{
int v = data[i];
newData[i] = v;
C[v]++;
}
for (int j=1; j<=K; j++)
{
C[j] += C[j-1];
}
for (int i=len-1; i>=0; i--)
{
int v = data[i];
newData[C[v]-1] = data[i];
C[v]--;
}
for (int i=0; i<len; i++)
{
data[i] = newData[i];
}
delete []newData;
}
//
// 基数排序
// 核心思想:k个计数排序
// 时间复杂度O(k*N);稳定
// 代码就略了。。。
//
// 桶排序
// 前提:已知元素在一定的区间,且符合均匀分布
// 核心思想:把区间分成n个大小相同的子区间,先对各个桶进行排序,然后依次输出即可
// 参考:http://hi.baidu.com/tzpwater/blog/item/5ef60d5a3ec24f9d810a1875.html
class element //element
{
public:
int value;
element *next;
element()
{
value=NULL;
next=NULL;
}
};
class bucket //bucket containing a range of values
{
public:
element *firstElement;
bucket()
{
firstElement = NULL;
}
};
void BucketSort(int *data, int len, int lowend, int highend)
{
int *array = data;
int interval=10;; //number of intervals
const int noBuckets=(highend-lowend)/interval; //number of buckets required
bucket *buckets=new bucket[noBuckets];
bucket *temp;
for(int a=0;a<noBuckets;a++) //creation of required buckets
{
temp=new bucket;
buckets[a]=*temp;
}
for(int j=0;j<len;j++) //sending elments into appropriate buckets
{
element *temp,*pre;
temp=buckets[array[j]/interval].firstElement;
if(temp==NULL)//if it is the first element of the bucket
{
temp=new element;
buckets[array[j]/interval].firstElement=temp;
temp->value=array[j];
}
else
{
pre=NULL;
while(temp!=NULL) //move till the appropriate position in the bucket
{
if(temp->value>array[j])
break;
pre=temp;
temp=temp->next;
}
if(temp != NULL && temp->value>array[j]) //if the new value is in betwen or at the begining
{
if(pre==NULL) //insertion at first if the bucket has elements already
{
element *firstNode;
firstNode=new element();
firstNode->value=array[j];
firstNode->next=temp;
buckets[array[j]/interval].firstElement=firstNode;
}
else //insertion at middle
{
element *firstNode;
firstNode=new element();
firstNode->value=array[j];
firstNode->next=temp;
pre->next=firstNode;
}
}
else// if the new value is to be created at last of bucket
{
temp=new element;
pre->next=temp;
temp->value=array[j];
}
}
}
// sort
int index = 0;
for(int jk=0;jk<10;jk++)
{
element *temp;
temp= buckets[jk].firstElement;
while(temp!=NULL)
{
data[index] = temp->value;
index++;
temp=temp->next;
}
}
delete []buckets;
}
//
int main()
{
///
int data[] = {49,38,65,97,76,13,27,49,55,04};
//InsertSort(data, 10);
//ShellSort(data, 10);
//SelectSort(data, 10);
//MergeSort(data, 0, 9);
//BubbleSort(data, 10);
//HeapSort(data, 10);
//QuickSort(data, 0, 9);
//output_array( data, 10);
//int data2[] = {3,4,5,1,2,3,3,4,2,3};
//CountingSort(data2, 10, 5);
//output_array( data2, 10);
int data3[] = {12,2,22,33,44,55,66,77,85,87,81,83,89,82,88,86,84,88,99};
BucketSort(data3, 19, 0, 100);
output_array( data3, 19);
return 0;
}
void output_array(int data[], int n)
{
int i;
for(i = 0; i < n; i++)
{
printf("%d ", data[i]);
}
printf("\n");
}
void exchange(int *a, int *b)
{
int x;
x = *a;
*a = *b;
*b = x;
}