序言:
内排序: 全部在内存里实现的成为内排序.
外排序: 不仅需要内存还需要外存成为排序.
五大分类: 插入排序,选择排序,交换排序,分配排序,归并排序;
一: 插入排序
1.1 直接插入排序:
从小到大: 时间复杂度: O() 排序是稳定的.
void DirectInsertionSort(int A[],int n)
{
for(int i = 1 ;i < n ;i++)
{
int j = i;
int temp = A[i];
while( j >=0 && temp < A[j-1])
{
A[j] = A[j-1];
j--;
}
A[j] = temp;
}
}
1.2 折半插入排序:
顾名思义, 在查找中利用二分法缩短时间:
时间复杂度: O()
void BinaryInsertionSort(int A[],int n)
{
for(int i = 1 ; i < n ; i++)
{
int temp = A[i];
int l = 0;
int r = i-1;
while(l <= r) {
int mid = (l+r)>>1;
if(temp <A[mid]) r = mid-1; // 前半部分查找位置
else
l = mid +1; // 后半部分查找位置
}
for(int j = i ; j > l ; j--) // 腾位置, l - i-1 右移一位
{
A[j] = A[j-1];
}
A[l] = temp; // 插进去
}
}
1.3 希尔排序(Shell)
分组, 组内一般采用直接插入法,
时间复杂度: O() 不稳定的
void ShellSort(int A[],int n,int s)
{
// 分组排序, 初始增量位s, 每循环一次, 减半 直到为0 为止;
for(int k = s;k >0 ;k>>=1)
{
for(int i = k ; i < n ; i++)
{
int temp = A[i];
int j = i-k;
// 组内排序,temp 插入组内合适的位置
while( j >=0 && temp < A[j]) {
A[j+k] = A[j];
j-=k;
}
A[j+k] = temp; // 插入
}
}
}
二:选择排序
2.1 直接选择排序:
每次从中选择最小的依次排序:
时间复杂度:O() 不稳定的;
void DirectSelectSort(int A[],int n)
{
for(int i = 0 ; i < n ; i++)
{
int temp = i;
for(int j = i + 1 ; j < n ; j++)
{
if(A[j] < A[temp])
temp = j;
}
if( i!= temp)
{
swap(A[temp],A[i]);
}
}
}
2.2 树形选择排序:(竞赛树排序,或胜者树)
时间复杂度: O(nlogn) 不稳定的;
代码-> 堆排序;
三: 交换排序
1.1 冒泡排序:
最简单的, 时间复杂度: O() 稳定的.
void BubbleSort(int A[],int n)
{
for(int i = 0 ; i < n;i++)
{
for(int j = n -1; j>i ;j--)
{
if(A[j-1] > A[j])
{
swap(A[j-1],A[j]);
}
}
}
}
3.2 快速排序:
时间复杂度: O(nlogn) 不稳定的;
递归实现:
void quicklySort(int A[],int low ,int high)
{
int mid = A[(low+high)>>1];
int l = low;
int r = high;
while(l < r) {
while(A[l] < mid) l++;
while(A[r] > mid) r--;
if( l <= r)
{
swap(A[l],A[r]);
l++,r--;
}
}
if( l < high) quicklySort(A,l,high);
if( r > low) quicklySort(A,low,r);
}
非递归实现: 用栈 (stack)
void QuickSortOfStack(int A[],int low, int high)
{
stack<int>S;
S.push(high);
S.push(low);
int l,r,mid;
while(!S.empty()) {
int templow = S.top();S.pop();
int temphigh = S.top();S.pop();
l = templow;
r = temphigh;
mid = A[(l+r)>>1];
while( l < r)
{
while(A[l] < mid ) l++;
while(A[r] > mid ) r--;
if( l <= r)
{
swap(A[l],A[r]);
l++,r--;
}
}
if( l < temphigh) S.push(temphigh),S.push(l);
if( r > templow ) S.push(r),S.push(templow);
}
}
四: 分配排序:
4.1 基数排序:
链表, 克服顺序存储所存在的空间和时间耗费问题.
时间复杂度:O() 是稳定的
typedef struct forSort
{
int key[3];
struct forSort *next;
}ForSort;
void RadixSort(ForSort *pData,int Clow,int Chigh,int d)
{
//pData 指针 头结节点, Clow 基数下阶, Chigh 基数上界
typedef struct{
ForSort *pHead;
ForSort *pTail;
}TempLink;
int r = Chigh - Clow +1 ;
TempLink *tlink;
ForSort *p;
int j;
tlink = new TempLink[sizeof(TempLink)*r];
for(int i = d-1 ; i >= 0; i--)
{
for( j = 0 ; j < r ; j++)
{
tlink[j].pHead = tlink[j].pTail = NULL;
}
for(p = pData; p!=NULL; p = p->next)
{
j = p->key[i]-Clow;
if(tlink[j].pHead ==NULL)
tlink[j].pHead = tlink[j].pTail = p;
else
{
tlink[j].pTail->next = p;
tlink[j].pTail = p;
}
}
int j = 0;
while(tlink[j].pHead ==NULL) j++;
pData = tlink[j].pHead;
p = tlink[j].pTail;
for(int k = j+1; k < r ; k++)
{
if(tlink[k].pHead !=NULL)
{
p->next = tlink[k].pHead;
p = tlink[k].pTail;
}
}
p->next = NULL;
}
for( p = pData; p!=NULL; p = p->next)
{
for(int i = 0 ; i <d ;i++)
printf("%d ", p->key[i]);
printf("\n");
}
free(tlink);
}
4.2 归并排序:
一般采用二路归并排序:
时间复杂度O(nlogn)
稳定
void TwoWayMerge(int Dst[],int Src[],int s, int e1,int e2)
{
/* 进行合并操作*/
int s1,s2;
for(s1 = s,s2 = e1+1 ; s1 <=e1 && s2 <= e2 ;)
{
if( Src[s1] <= Src[s2])
Dst[s++] = Src[s1++];
else
Dst[s++] = Src[s2++];
}
if( s1 <= e1)
memcpy(&Dst[s],&Src[s1],(e1-s1+1)*sizeof(int));
else
memcpy(&Dst[s],&Src[s2],(e2-s2+1)*sizeof(int));
}
void OnePassMerge(int Dst[],int Src[],int len , int n)
{
int i;
/* 按照 k分组 每次 对 2个组从开头到结尾 进行合并*/
for(i = 0 ; i < n- 2*len; i += 2*len)
{
TwoWayMerge(Dst,Src,i,i+len-1,i+2*len-1);
}
/* 还有剩余 最多还俩2 */
if(i < n-len)
{
TwoWayMerge(Dst,Src,i,i+len-1,n-1);
}
else
memcpy(&Dst[i],&Src[i],(n-i)*sizeof(int));/* 还有一个 直接复制过去*/
}
int B[120];
/* 二路归并排序*/
void MergeSort(int A[],int n)
{
for(int k = 1 ; k < n ; )
{
memset(B,0,sizeof(B));
OnePassMerge(B,A,k,n); /*先把A暂存到B中*/
k<<=1; /* B *2 */
if( k >= n)
{
memcpy(A,B,n*sizeof(int)); /* 归并完, 把暂存在B中还给A*/
}
else{
/* 归并排序*/
OnePassMerge(A,B,k,n);
k<<=1;
}
}
}