排序算法及其应用(C++实现)

排序算法及其应用(C++实现)

一、 常见排序算法:
冒泡排序、选择排序、插入排序、归并排序、快速排序、堆排序…

冒泡排序:
  从第0号元素到第n-1号元素遍历,若前面一个元素大于后面一个元素,则交换两个元素,这样可将整个序列中最大的元素冒泡到最后。然后再从第0号到第n-2号遍历,如此往复,直到只剩一个元素。

void bubbleSort(int a[], int n){
    for(int i = 0; i < n; ++i){
        for(int j = 0; j < n-i-1; ++j){
            if(a[j] > a[j+1])
                swap(a[j], a[j+1]);
        }
    }
}

选择排序:
  从全部序列中选取最小的,与第0个元素交换,然后从第1个元素往后找出最小的,与第一个元素交换,再从第2个元素往后选取最小的,与第2个元素交换,直到选取最后一个元素。

void selectSort(int a[], int n){
    for(int i = 0; i < n; ++i){
        int minIndex = i;
        for(int j = i+1; j < n; ++j){
            if(a[j] < a[minIndex])
                minIndex = j;
        }
        swap(a[minIndex], a[i]);
    }
}

插入排序:
  思路类似扑克牌的排序,每次从未排序序列的第一个元素,插入到已排序序列中的合适位置。假设初始的有序序列为第0个元素(本文描述的序号都从0开始),只有一个元素的序列肯定是有序的,然后从原先序列的第1个元素开始到第n-1个元素遍历,每次将当前元素插入到它之前序列中的合适位置。

void insertSort(int a[], int n){
    for(int i = 1; i < n; ++i){
        int val = a[i];
        int j;
        for(j = i - 1; j >= 0 && a[j] > val; --j)
            a[j+1] = a[j];
        a[j+1] = val;
    }
}

归并排序:
  归并排序的思想是,利用二分的特性,将序列分成两个子序列进行排序,将排序后的两个子序列归并(合并),当序列的长度为2时,它的两个子序列长度为1,即视为有序,可直接合并,即达到归并排序的最小子状态。

void mergeSort_Recursive(int a[], int b[], int start, int end){
    if(start >= end)
        return;
    int mid = start + (end - start)/2;
    int start1 = start, end1 = mid;
    int start2 = mid + 1, end2 = end;
    mergeSort_Recursive(a, b, start1, end1);
    mergeSort_Recursive(a, b, start2, end2);
    int i = start;
    while(start1 <= end1 && start2 <= end2)
        b[i++] = a[start1] < a[start2]? a[start1++] : a[start2++];
    while(start1 <= end1)
        b[i++] = a[start1++];
    while(start2 <= end2)
        b[i++] = a[start2++];
    for(int i = start; i <= end; ++i)
        a[i] = b[i];
}
void mergeSort(int a[], int n){
    int* b = new int[n];
    mergeSort_Recursive(a, b, 0, n-1);
    delete[] b;
}

快速排序:
  快排的思想是,选取第一个数为基准,通过一次遍历将小于它的元素放到它的左侧,将大于它的元素放到它的右侧,然后对它的左右两个子序列分别递归地执行同样的操作。总之,快速排序利用分而治之的思想。

int partition(int a[], int left, int  right){
    int pivot = a[left];
    int i = left;
    for(int j = left; j < right; ++j){
        if(a[j] < pivot){
            swap(a[++i], a[j]);
        }
    }
    swap(a[i], a[left]);
    return i;
}

void quickSort(int a[], int left, int right){      //左闭右开
    if(left < right){
        int i = left + rand() % (right - left);    //将主元放在首位置
        swap(a[left], a[i]);
        int p = partition(a, left, right);
        quickSort(a, left, p);
        quickSort(a, p + 1, right);
    }
}

堆排序:
  堆排序利用的是二叉树的思想,所谓堆就是一个完全二叉树。堆排序分两个流程,首先是构建大顶堆,然后是从大顶堆中获取按逆序提取元素。首先是大顶堆,大顶堆即一个完全二叉树,每一个节点都大于它的所有子节点。大顶堆可以按照从上到下从左到右的顺序,用数组来存储,第i个节点的父节点序号为(i-1)/2,左子节点序号为2i+1,右子节点序号为2(i+1)

void heapify(int a[], int node, int size){
    int left = 2*node + 1;
    int right = 2*(node + 1);
    int max = node;
    if(left < size && a[left] > a[max])
        max = left;
    if(right < size && a[right] > a[max])
        max = right;
    if(max != node){
        swap(a[max], a[node]);
        heapify(a, max, size);             //使交换后的子子树也满足最大堆
    }
}
void heapSort(int a[], int n){
    for(int i = (n-1)/2; i >= 0; --i)      //最后一个叶子节点的父节点为(n-1)/2
        heapify(a, i, n);                  //构造最大堆
    for(int i = n-1; i >= 0; --i){
        swap(a[0], a[i]);                  //将当前最大数放置在数组末尾
        heapify(a, 0, i);                  //将新产生的未排序部分继续进行堆排序
    }
}

算法测试:

int main(){
    int a[8] = {2,1,5,4,3,6,8,7};
    int n = sizeof(a)/sizeof(a[0]);

    cout << "before sorting:\n";
    for(int i = 0; i < n; ++i)
        cout << a[i] << " ";
    cout << "\n";

    //bubbleSort(a, n);

    //selectSort(a, n);

    //insertSort(a, n);

    //mergeSort(a, n);

    //quickSort(a, 0, n);

    heapSort(a, n);

    cout << "after Sorting:\n";
    for(int i = 0; i < n; ++i)
        cout << a[i] << " ";
    cout << "\n";

    return 0;
}

二、各类排序算法算法复杂度:

算法时间复杂度空间复杂度稳定性
冒泡排序双层循环,O(n2)不需要额外空间, O(1)稳定
选择排序双层循环,O(n2)不需要额外空间, O(1)不稳定
插入排序双层循环,O(n2)不需要额外空间, O(1)稳定
归并排序时间复杂度O(nlogn)需要额外空间, O(n)稳定
快速排序时间复杂度O(nlogn)不需要额外空间, O(1)不稳定
堆排序时间复杂度O(nlogn)不需要额外空间, O(1)不稳定

三、 各类排序算法适用情况:

(1)当数据规模较小时候,可以使用插入排序或者选择排序

(2)当文件的初态已经基本有序,可以用插入排序冒泡排序

(3)当数据规模较大时,应用速度最快的排序算法,可以考虑使用快速排序

(4)要求排序时是稳定的,可以考虑用归并排序

  快速排序是目前基于比较的内部排序中被认为是最好的方法,当待排序的关键字是随机分布时,快速排序的平均时间最短;堆排序所需的辅助空间少于快速排序,并且不会出现快速排序可能出现的最坏情况。这两种排序都是不稳定的。若要求排序稳定,则可选用归并排序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值