部分排序实现:
插入排序
1.直接插入排序
原理:将数组分为无序区和有序区两个区,然后不断将无序区的第一个元素按大小顺序插入到有序区中去,最终将所有无序区元素都移动到有序区完成排序。
要点:设立哨兵,作为临时存储和判断数组边界之用。
实现:
void InsertSort(int *p_iSort, int p_ilength)
{
/* p_iAfterSort = new int[p_ilength];
memset((void*) p_iAfterSort, 0x00, sizeof(int) * p_ilength);*/
int iIndex = 0, iIndex2 = 0;
int temp = 0;
for (iIndex = 1; iIndex < p_ilength; iIndex ++)
{
iIndex2 = iIndex – 1;
if (p_iSort[iIndex2] > p_iSort[iIndex])
{
temp = p_iSort[iIndex];
while (p_iSort[iIndex2] > temp && iIndex2 >= 0)
{
p_iSort[iIndex2 + 1] = p_iSort[iIndex2];
iIndex2 — ;
}
p_iSort[iIndex2 + 1] = temp;
}
}
}
2.希尔排序
原理:又称增量缩小排序。先将序列按增量划分为元素个数相同的若干组,使用直接插入排序法进行排序,然后不断缩小增量直至为1,最后使用直接插入排序完成排序。
要点:增量的选择以及排序最终以1为增量进行排序结束。
实现:
void shellSort(int *p_iSort, int p_ilength)
{
int iTempLenth = 0, iIndex = 0, iIndex_2 = 0, temp = 0;
for(iTempLenth = p_ilength/2; iTempLenth >= 1; iTempLenth = iTempLenth/2) // 长度折半
{
for(iIndex = iTempLenth; iIndex < p_ilength; iIndex ++) // 直接插入排序算法
{
temp = p_iSort[iIndex];
for(iIndex_2 = iIndex – iTempLenth;(iIndex_2 >= 0) && (p_iSort[iIndex_2] > temp); iIndex_2 = iIndex_2 – iTempLenth)
{
p_iSort[iIndex_2 + iTempLenth] = p_iSort[iIndex_2];
}
p_iSort[iIndex_2 + iTempLenth] = temp;
}
}
}
交换排序
1.冒泡排序
原理:将序列划分为无序和有序区,不断通过交换较大元素至无序区尾完成排序。
要点:设计交换判断条件,提前结束以排好序的序列循环。
实现:
// 冒泡排序
void BubbleSort(int *p_iSort, int p_ilength)
{
int iIndex = 0, iIndex_2 = 0;
bool bunSorted = false;
for (iIndex = p_ilength – 1; iIndex >= 0; iIndex –)
{
bunSorted = false;
for (iIndex_2 = 0; iIndex_2 < iIndex; iIndex_2 ++)
{
if (p_iSort[iIndex_2] > p_iSort[iIndex_2 + 1])
{
int iTemp = p_iSort[iIndex_2 + 1];
p_iSort[iIndex_2 + 1] = p_iSort[iIndex_2];
p_iSort[iIndex_2] = iTemp;
bunSorted = true;
}
}
if (!bunSorted)
{
break;
}
}
}
2.快速排序
原理:不断寻找一个序列的中点,然后对中点左右的序列递归的进行排序,直至全部序列排序完成,使用了分治的思想。
要点:递归、分治
实现:
int QuickSortStep(int p_iSort[], int p_iLow, int p_iHigh)
{
// assert(p_iSort[p_iLow] != 0x00);
int key = p_iSort[p_iLow];
while (p_iLow < p_iHigh)
{
while (p_iSort[p_iHigh] >= key && p_iLow < p_iHigh)
{
p_iHigh –;
}
p_iSort[p_iLow] = p_iSort[p_iHigh];
while (p_iSort[p_iLow] <= key && p_iLow < p_iHigh)
{
p_iLow ++;
}
p_iSort[p_iHigh] = p_iSort[p_iLow];
}
p_iSort[p_iLow] = key;
return p_iHigh;
}
void QuickSort(int p_iSort[], int p_iLow, int p_iHigh)
{
if (p_iLow >= p_iHigh) return;
int index = QuickSortStep(p_iSort, p_iLow, p_iHigh); //完成一次单元排序
QuickSort(p_iSort, p_iLow, index – 1);
QuickSort(p_iSort, index + 1, p_iHigh);
}
选择排序
1.直接选择排序
原理:将序列划分为无序和有序区,寻找无序区中的最小值和无序区的首元素交换,有序区扩大一个,循环最终完成全部排序。
要点:
实现:
Void SelectSort(Node L[])
{
Int i,j,k;//分别为有序区,无序区,无序区最小元素指针
For(i=0;i<length;i++)
{
k=i;
For(j=i+1;j<length;j++)
{
If(L[j]<L[k])
k=j;
}
If(k!=i)//若发现最小元素,则移动到有序区
{
Int temp=L[k];
L[k]=L[i];
L[i]=L[temp];
}
}
}
2.堆排序
原理:利用大根堆或小根堆思想,首先建立堆,然后将堆首与堆尾交换,堆尾之后为有序区。
要点:建堆、交换、调整堆
实现:
Void HeapSort(Node L[])
{
BuildingHeap(L);//建堆(大根堆)
For(int i=n;i>0;i–)//交换
{
Int temp=L[i];
L[i]=L[0];
L[0]=temp;
Heapify(L,0,i);//调整堆
}
}
Void BuildingHeap(Node L[])
{ For(i=length/2 -1;i>0;i–)
Heapify(L,i,length);
}
归并排序
原理:将原序列划分为有序的两个序列,然后利用归并算法进行合并,合并之后即为有序序列。
要点:归并、分治
实现:
Void MergeSort(Node L[],int m,int n)
{
Int k;
If(m<n)
{
K=(m+n)/2;
MergeSort(L,m,k);
MergeSort(L,k+1,n);
Merge(L,m,k,n);
}
}
基数排序
原理:将数字按位数划分出n个关键字,每次针对一个关键字进行排序,然后针对排序后的序列进行下一个关键字的排序,循环至所有关键字都使用过则排序完成。
要点:对关键字的选取,元素分配收集。
实现:
Void RadixSort(Node L[],length,maxradix)
{
Int m,n,k,lsp;
k=1;m=1;
Int temp[10][length-1];
Empty(temp); //清空临时空间
While(k<maxradix) //遍历所有关键字
{
For(int i=0;i<length;i++) //分配过程
{
If(L[i]<m)
Temp[0][n]=L[i];
Else
Lsp=(L[i]/m)%10; //确定关键字
Temp[lsp][n]=L[i];
n++;
}
CollectElement(L,Temp); //收集
n=0;
m=m*10;
k++;
}
}
部分算法复杂度:
1.插入排序:每次将一个待排的记录插入到前面的已经排好的队列中的适当位置。
①.直接插入排序
直接排序法在最好情况下(待排序列已按关键码有序),每趟排序只需作1次比较而不需要移动元素。所以n个元素比较次数为n-1,移动次数0。
最差的情况下(逆序),其中第i个元素必须和前面的元素进行比较i次,移动个数i+1,所以总共的比较次数 比较多,就不写出来了
总结:是一种稳定的排序方法,时间复杂度O(n^2),排序过程中只要一个辅助空间,所以空间复杂度O(1)
②.希尔排序
缩小增量排序,对直接插入排序的一种改进
分组插入方法。
总结:是一种不稳定的排序方法,时间复杂度O(n^1.25),空间复杂度O(1)
2.交换排序
①.冒泡排序
最好的情况下,就是正序,所以只要比较一次就行了,复杂度O(n)
最坏的情况下,就是逆序,要比较n^2次才行,复杂度O(n^2)
总结:稳定的排序方法,时间复杂度O(n^2),空间复杂度O(1),当待排序列有序时,效果比较好。
②.快速排序
通过一趟排序将待排的记录分割成独立的两部分,其中一部分记录的关键字均比另一个部分的关键字小,然后再分别对这两个部分记录继续进行排序,以达到整个序列有效。
总结:在所有同数量级O(nlogn)的排序方法中,快速排序是性能最好的一种方法,在待排序列无序时最好。算法的时间复杂度是O(nlogn),最坏的时间复杂度O(n^2),空间复杂度O(nlogn)
3.选择排序
①.直接选择排序
和序列的初始状态无关
总结:时间复杂度O(n^2),无论最好还是最坏
②.堆排序
直接选择排序的改进
总结:时间复杂度O(nlogn),无论在最好还是最坏情况下都是O(nlogn)
4.归并排序
总结:时间复杂度O(nlogn),空间复杂度O(n)
5.基数排序
按组成关键字的各个数位的值进行排序,是分配排序的一种。不需要进行排码值间的比较就能够进行排序。
总结:时间复杂度O(d(n+rd))
总总结:
n比较小的时候,适合 插入排序和选择排序
基本有序的时候,适合 直接插入排序和冒泡排序
n很大但是关键字的位数较少时,适合 链式基数排序
n很大的时候,适合 快速排序 堆排序 归并排序
无序的时候,适合 快速排序
稳定的排序:冒泡排序 插入排序 归并排序 基数排序
复杂度是O(nlogn):快速排序 堆排序 归并排序
辅助空间(大 次大):归并排序 快速排序
好坏情况一样:简单选择(n^2),堆排序(nlogn),归并排序(nlogn)
最好是O(n)的:插入排序 冒泡排序