一.常用算法分类
1.非线性时间
比较类排序 :快速排序和冒泡排序
插入类排序 :简单插入排序和希尔排序
选择类排序 :简单选择排序和堆排序
归并排序 :二路归并排序和多路归并排序
2.线性时间
非比较类排序 :计数排序、基数排序、桶排序
二.算法复杂度
三.算法实现
1.冒泡排序原理
从数组中第一个数开始,依次遍历数组中的每一个数,通过相邻比较交换,每一轮循环下来找出剩余未排序数的中的最大数并”冒泡”至数列的顶端。
void bubbleSort(int n){
int i,j;
for(i=1;i<=n;i++){ //两重循环依次遍历比较
for(j=1;j<n;j++){
if(a[j]>a[j+1]){
int t = a[j];
a[j] = a[j+1];
a[j+1] = t;
}
}
}
}
2.快速排序原理
1.找一个基准数,从后向前找,直到遇到第一个比它小的数;从前往后找,直到遇到第一个比它大的数,将两个数交换位置
2.依次遍历直到i和j相遇
3.将基准数与标记为i的数交换位置,至此数组完成第一次遍历,以基准数为中心,左边的都比它小,后边的都比它大
4.对左右两组数组进行递归遍历
5.当左右标记相等时,标志着排序完成
void quickSort(int left,int right){
int i,j,temp;
if(left > right)
return;
temp = a[left]; //作为基准数
i = left;
j = right;
while(i!=j){
while(a[j] >= temp&&i < j){ //从右向左依次遍历
j--;
}
while(a[i] <= temp&&i < j){ //从左向右依次遍历
i++;
}
if(i<j){ //交换获取的元素
int t = a[i];
a[i] = a[j];
a[j] = t;
}
}
a[left] = a[i];
a[i] = temp;
quickSort(left,i-1); //递归遍历数组
quickSort(i+1,right);
}
3. 简单插入排序原理
1.从第一个元素开始,该元素可以认为已经被排序;
2.取出下一个元素,在已经排序的元素序列中从后向前扫描;
3.如果该元素(已排序)大于新元素,将该元素移到下一位置;
4.重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
5.将新元素插入到该位置后;
6.如果新元素大于该元素(已排序),则新元素就在该位置 ;
7.重复步骤2~5;
void insertionSort(int n){
int temp;
for(int i=2;i<=n;i++){
int j = i-1;
temp = a[i];
while(j>=1&&a[j]>temp){
a[j+1] = a[j];
j--;
}
a[j+1] = temp;
}
}
4.希尔排序原理:
Shell排序法是对相邻指定距离(称为增量)的元素进行比较,并不断把增量缩小至1,完成排序。
1.一般初始增量是len/2,分为len/2组,每组两个元素,用插入排序比较
2.将增量/2;分为len/4组,每组元素用插入排序比较
3.直至增量为1,变为一趟直接插入排序完成整个排序过程
void shellSort(int a[],int n){
for(int gap = n/2;gap>=1;gap/=2){
for(int i=gap;i<=n;i++){
int j=i-gap;
int temp = a[i];
while(j>=1&&temp<a[j]){
a[j+gap] = a[j];
j -= gap;
}
if((j+gap) !=i){
a[j+gap] = temp;
}
}
}
}
5.简单选择排序原理:
1.取第一个数作为基准数,它与剩下所有数比较,得到最小数的标记
2.最小数与第一个数交换位置,最小数来到应该到的位置
3.依次重复n次
void selectSort(int n){
int i,j,k;
for(i=1;i<=n;i++){
k=i;
for(j=i+1;j<=n;j++){
if(a[j]<a[k]){
k=j;
}
}
if(i!=k){
int t=a[i];
a[i]=a[k];
a[k]=t;
}
}
}
6.堆排序原理:
1.将待排序序列构造成一个大顶堆(升序),然后堆顶就是整个序列的最大值与数组尾的元素交换
2.将剩下n-1个元素重复执行
3.得到有序序列
从最后一个非叶子结点开始(arr.length-1),即左叶子节点先与右叶节点比较
得到的大的元素与其父节点比较,知道根节点,这样完成第一次大顶堆
交换堆顶和数组最后一个元素位置,再从n-1开始重新构建大顶堆
重复n-1次完成有序序列
void adjustHeap(int i,int n){
int temp = a[i];
for(int k=2*i+1;k<n;k=k*2+1){
if(k+1<n&&a[k]<a[k+1]){
k++;
}
if(a[k]>temp){
a[i] = a[k];
i = k;
}
else
break;
}
a[i] = temp;
}
void heapSort(int n){
for(int i=n/2-1;i>=0;i--){
adjustHeap(i,n);
}
for(int j = n-1;j>0;j--){
int t = a[0];
a[0] = a[j];
a[j] = t;
adjustHeap(0,j);
}
}
7.二路归并排序原理:
将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
1. 将无序的原始序列左右分组,直到序列只有2个元素
2.对其进行比较排序
3.一层层返回,直到得到有序的序列
void Merge(int sourcrArr[],int tempArr[],int startIndex,int midIndex,int endIndex)
{
int i=startIndex,j=midIndex+1,k=startIndex;
while (i!=midIndex+1&&j!=endIndex+1) {
if (sourcrArr[i]>sourcrArr[j]) {
tempArr[k++]=sourcrArr[j++];
}
else
tempArr[k++]=sourcrArr[i++];
}
while (i!=midIndex+1) {
tempArr[k++]=sourcrArr[i++];
}
while (j!=endIndex+1) {
tempArr[k++]=sourcrArr[j++];
}
for (i=startIndex; i<=endIndex; i++) {
sourcrArr[i]=tempArr[i];
}
}
void MergeSort(int sourcrArr[],int tempArr[],int startIndex,int endIndex)
{
int midIndex;
if (startIndex<endIndex) {
midIndex=(startIndex+endIndex)/2;
MergeSort(sourcrArr, tempArr, startIndex, midIndex);
MergeSort(sourcrArr, tempArr, midIndex+1, endIndex);
Merge(sourcrArr, tempArr, startIndex, midIndex, endIndex);
}
}
8. 计数原理:
(适用于小范围集合的排序)
1.取另一数组以无序数组的值作为标记,记录出现的次数
2.对所有的计数累加,即该数组的某一标记记录了小于等于该标记数组值之和;
3.反向填充新数组,cout[a[i]]-1作为新数组的标记,记录a[i]的值
void countSort(int a[],int n){
int i;
for(i=0;i<n;i++){
b[a[i]]++;
}
for(i=1;i<1000;i++){
b[i] += b[i-1];
}
for(i=n;i>0;i--){
c[b[a[i-1]]-1] = a[i-1];
b[a[i-1]]--;
}
}
9. 基数排序原理:
它是透过键值的部分信息,将要排序的元素分配至某些“桶”中,藉以达到排序的作用。
基数排序(以整形为例),将整形10进制按每位拆分,然后从低位到高位依次比较各个位。主要分为两个过程:
(1)分配,先从个位开始,根据位值(0-9)分别放到0~9号桶中;
(2)收集,再将放置在0~9号桶中的数据按顺序放到数组中;
int getDigitInPos(int num,int pos){ //用于得到位数
int i,temp = 1;
for(i=0;i<pos-1;i++){
temp *=10;
}
return (num/temp)%10;
}
void radixSort(int n){
int i,j;
for(i=0;i<10;i++){
radix[i][0]=0;
}
for(int pos = 1;pos<=10;pos++){
for(i=0;i<n;i++){
int num = getDigitInPos(a[i],pos); //获取每个位数的数字
int index = ++radix[num][0];
radix[num][index] = a[i];
}
for(i=0,j=0;i<10;i++){
for(int k = 1;k<=radix[i][0];k++){
a[j++] = radix[i][k];
}
radix[i][0]=0;
}
}
}
10. 桶排序原理:
桶排序 (Bucket sort)的工作的原理:假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序
1.设置一个定量是数组作为空桶
2.遍历输入数组,以元素作为下标放于对应桶中
3.对每个不是空的桶进行排序
4.从不是空的桶里把排序好的数据拿出。
void bucketSort(int n){
int max=0,i;
for(i=0;i<n;i++){
if(max<a[i]){
max = a[i];
}
}
for(i=0;i<n;i++){
arr[a[i]]++;
}
for(int j=0,i=0;j<=max;j++){
while(arr[j]-->0){
a[i++] = j;
}
}
}