几种排序算法总结

注:以下所有排序算法都是按照整数值从小到大排序。


冒泡排序


思想:对于一个序列,走一趟把最大数冒到最后面。
示例:对于序列4, 10, 1, 6, 2, 7, 3, 8如下图(红框表示下一趟需要处理的子序列)
这里写图片描述

即总共需要走n趟,当第i趟走完时倒数i个数是有序的。

代码

 for(i = 0; i < n; i++) {//需要走n趟
        for(j = 0; j < n - i - 1; j++) {//后面i个元素已经有序了不用管
            if(a[j] > a[j + 1]) {//不断地把较大的数后移
                int temp = a[j];
                a[j] = a[j + 1];
                a[j + 1] = temp;
            }
        }
    }

优化:由上面的示意图可知,当第4趟走完时序列已经完全排好序了,后面的几趟都是多余的。因此可以弄一个标记变量,假如在某一趟中没有发生交换则说明对于任意两个相邻的元素都满足前者<后者,也就是序列已经排好序了,因此可以提前结束。

时间复杂度:O(n^2),空间复杂度O(1),稳定性:稳定。
总结:走n趟,第i趟将前n-i+1个元素的最大数冒到最后面。


选择排序


思想:对于一个序列,走一趟就把选到的最小数放在该序列的最前面。
示例:对于序列4, 10, 1, 6, 2, 7, 3, 8如下图
这里写图片描述

代码

for(i = 0; i < n; i++) {
        int index = i;
        for(j = i; j < n; j++) {//前面i-1个元素已经有序了
            if(a[j] < a[index]) {//寻找后n-i+1个元素的最小数下标位置
                index = j;
            }
        }
        if(index != i) {//将找到的最小数放在最前面
            int temp = a[index];
            a[index] = a[i];
            a[i] = temp;
        }
    }

时间复杂度:O(n^2),空间复杂度O(1),稳定性:不稳定。
总结:走n趟,第i趟将后n-i+1个元素的最小数选择放到最前面。


插入排序


思想:对于后面n-1个数,依次插入到前面的有序序列。
示例:对于序列4, 10, 1, 6, 2, 7, 3, 8如下图
这里写图片描述

代码(直接插入法)

   for(i = 1; i < n; i++) {//从第2个元素开始
      for(j = i - 1; j >= 0; j--) {//将a[i]插入到前面有序的序列中
         if(a[j + 1] < a[j]) {
            int temp = a[j];
            a[j] = a[j+1];
            a[j+1] = temp;
         } else {
            break;
        }
      }
   }

时间复杂度:O(n^2),空间复杂度O(1),稳定性:稳定。
总结:将后n-1个元素逐个插入到前面的有序序列中


快速排序


思想:分治排序每一部分,而排序采用partition方法进行。
示例:对于序列4, 10, 1, 6, 2, 7, 3, 8。Partition过程:

这里写图片描述

代码

//对a[left]~a[right]进行划分
int partition(int a[], int left, int right) {
    if(left > right || left < 0) {
        return -1;//出错
    } else {
        int base = a[left];
        int low, high;
        low = left;
        high = right;
        while(low < high) {
            //右指针寻找第一个小于base的数的位置
            while(low < high && a[high] >= base) {
                high--;
            }
            //如果找到则放到low指针指向的位置
            if(low < high) {
                a[low] = a[high];
                low++;
            }
            //左指针寻找第一个大于等于base的数的位置
            while(low < high && a[low] < base) {
                low++;
            }
            //如果找到则放在high指针指向的位置
            if(low < high) {
                a[high] = a[low];
                high--;
            }
        }
        //此时low一定等于high
        //将基准值放在中间位置并返回
        a[low] = base;
        return low;
    }
}

//对a[left]~a[right]排序
void quickSort(int a[], int left, int right) {
    if(left < right) {
        int mid = partition(a, left, right);
        quickSort(a, left, mid - 1);
        quickSort(a, mid + 1, right);
    }
}

时间复杂度:最好情况O(nlogn),最坏情况O(n^2),平均情况O(nlogn)。空间复杂度:所需栈空间O(logn)~O(n)。稳定性:不稳定


堆排序


思想:利用堆进行调整使得堆上的元素有序。
代码:

void siftDDown(int a[], int p, int len) {
    int temp;
    int child = 2 * p + 1;
    while(child < len) {
        //有右孩子且右孩子更小
        if(child + 1 <len && a[child] > a[child + 1]) {
            child++;
        }
        if(a[p] > a[child]) {
            temp = a[p];
            a[p] = a[child];
            a[child] = temp;
            p = child;
            child = 2 * p + 1;
        } else {
            break;
        }
    }
}

int main()
{
    int a[] = {4, 10, 1, 6, 2, 7, 3, 8};
    int n = 8;
    int i;
    //建立小根堆
    for(i = n/2 - 1; i>= 0; i--) {
        siftDDown(a, i, n);
    }
    //不断取出堆顶元素
    for(i = n - 1; i >= 0; i--) {
        cout<<a[0]<<" ";
        a[0] = a[i];
        siftDDown(a, 0, i);
    }
    cout<<endl<<endl;

    return 0;
}

时间复杂度:最好情况O(nlogn),最坏情况O(nlogn),平均情况O(nlogn)。空间复杂度:O(1)。稳定性:不稳定


归并排序


代码:

//合并a[start]~a[mid]和a[mid+1]~a[end]
void merge(int a[], int start, int mid, int end) {
    if(start > mid || mid + 1 > end) {
        return;
    }
    int p = start, q = mid + 1;
    //临时空间
    int *temp = new int[end - start + 1];
    int k = 0;
    while(p <= mid && q <= end) {
        if(a[p] <= a[q]) {
            temp[k++] = a[p++];
        } else {
            temp[k++] = a[q++];
        }
    }
    while(p <= mid) {
        temp[k++] = a[p++];
    }
    while(q <= end) {
        temp[k++] = a[q++];
    }
    //
    for(int i = start; i <= end; i++) {
        a[i] = temp[i - start];
    }
    delete []temp;
}

void mergeSort(int a[], int start, int end) {
    if(start < end) {
        int mid = (start + end) / 2;
        mergeSort(a, start, mid);//a[start...mid]
        mergeSort(a, mid + 1, end);//a[mid+1...end]
        merge(a, start, mid, end);
    }
}

时间复杂度:最好情况O(nlogn),最坏情况O(nlogn),平均情况O(nlogn)。空间复杂度:O(n)。稳定性:稳定


几种排序算法对比


这里写图片描述

说明:如果最好情况与最坏情况的时间复杂度不一样,则说明初始数据集的排列顺序对该算法的性能有影响。



转载请注明出处:http://blog.csdn.net/u012619640/article/details/50650054

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值