几种常用的排序算法(C++实现冒泡,插入,选择,堆排序)

c++11

在ubuntu 18.04上通过编译和调试

以下代码均是从小到大排序

冒泡排序

 1 /*
 2  * BubbleSort.h
 3  * 冒泡排序
 4  *  Created on: 2020年2月10日
 5  *      Author: LuYonglei
 6  */
 7 
 8 #ifndef SRC_BUBBLESORT_H_
 9 #define SRC_BUBBLESORT_H_
10 #include <vector>
11 using namespace std;
12 
13 #if 0
14 
15 template<typename T>
16 void bubbleSort(vector<T> &arr) {
17     //冒泡排序,从小到大(数组存在提前有序的情况下可以优化,但此情况出现概率较低)
18     for (int end = arr.size() - 1; end > 0; end--) {
19         //外层循环控制遍历次数
20         bool sorted = true; //优化添加的标记
21         for (int begin = 1; begin <= end; begin++) {
22             //内层循环控制比较和交换次数
23             if (arr[begin] < arr[begin - 1]) {
24                 swap(arr[begin], arr[begin - 1]);
25                 sorted = false;
26             }
27         }
28         //若已经有序,则提前退出排序
29         if (sorted)
30             break;
31     }
32 }
33 #else
34 
35 template<typename T>
36 void bubbleSort(vector<T> &arr) {
37     //冒泡排序,从小到大(如果序列尾部局部有序,可以记录最后一次交换位置,减少比较次数)
38     for (int end = arr.size() - 1; end > 0; end--) {
39         //外层循环控制遍历次数
40         int sortedIndex = 0; //优化添加的索引(此索引不可以随便设置,为数据完全有序做准备,若完全有序会提前退出)
41         for (int begin = 1; begin <= end; begin++) {
42             //内层循环控制比较和交换次数
43             if (arr[begin] < arr[begin - 1]) {
44                 swap(arr[begin], arr[begin - 1]);
45                 sortedIndex = begin;
46             }
47         }
48         //记录最后一次交换位置,减少比较次数
49         end = sortedIndex;
50     }
51 }
52 
53 #endif
54 
55 #endif /* SRC_BUBBLESORT_H_ */

选择排序

/*
 * SelectionSort.h
 * 选择排序(选择排序交换次数远远小于冒泡排序,所以平均性能比冒泡排序要好)
 *  Created on: 2020年2月10日
 *      Author: LuYonglei
 */

#ifndef SRC_SELECTIONSORT_H_
#define SRC_SELECTIONSORT_H_
#include <vector>
using namespace std;

#if 1

template<typename T>
void selectionSort(vector<T> &arr) {
    //从序列中选择最大的元素,与末尾元素交换位置
    for (int end = arr.size() - 1; end > 0; end--) {
        int maxIndex = 0; //最大元素的索引
        for (int begin = 0; begin <= end; begin++) {
            if (arr[begin] >= arr[maxIndex])
                maxIndex = begin; //保留最大元素位置的索引(要保证排序算法的稳定性,需要加=)
        }
        swap(arr[maxIndex], arr[end]); //选择最大的元素,与末尾元素交换位置
    }
}
#else
//利用堆来选择最值,配合排序算法可以降低算法复杂度,所以衍生出了堆排序
#endif

#endif /* SRC_SELECTIONSORT_H_ */

插入排序

插入排序使用的BinarySearch.h

/*
 * BinarySearch.h
 * 二分查找
 * 数组取值范围尽量保证左闭右开,这样end-begin=size,编码比较方便
 *  Created on: 2020年2月11日
 *      Author: LuYonglei
 */

#ifndef SRC_BINARYSEARCH_H_
#define SRC_BINARYSEARCH_H_
#include <vector>
using namespace std;
#define ELEMENT_NOT_FIND -1

//查找value在有序数组arr中的位置
template<typename T>
int indexOf(const vector<T> &arr, int size, T value) {
    int arraySize = arr.size();
    if (arraySize == 0 || size <= 0 || arraySize < size)
        return ELEMENT_NOT_FIND;
    int begin = 0; //最前面元素的索引
    int end = size; //最后一个元素索引的下一个
    while (begin < end) {
        int middle = (begin + end) / 2;
        if (value < arr[middle]) {
            end = middle;
        } else if (value > arr[middle]) {
            begin = middle + 1;
        } else {
            //value==arr[mid]
            return middle;
        }
    }
    return ELEMENT_NOT_FIND;
}

//查找value在有序数组arr中待插入的位置
//有序数组中第一个大于value的位置
template<typename T>
int indexOfInsertion(const vector<T> &arr, int size, T value) {
    //为了保证二分查找后再插入的稳定性
    int arraySize = arr.size();
    if (arraySize == 0 || size <= 0 || arraySize < size)
        return ELEMENT_NOT_FIND;
    int begin = 0; //最前面元素的索引
    int end = size; //最后一个元素索引的下一个
    while (begin < end) {
        int middle = (begin + end) / 2;
        if (value < arr[middle]) {
            end = middle;
        } else {
            //value >= arr[middle]
            begin = middle + 1;
        }
    }
    //此时begin==end
    return begin;
}

#endif /* SRC_BINARYSEARCH_H_ */

以下是插入排序的具体实现

/*
 * InsertionSort.h
 * 插入排序
 *  Created on: 2020年2月11日
 *      Author: LuYonglei
 */

#ifndef SRC_INSERTIONSORT_H_
#define SRC_INSERTIONSORT_H_
#include <vector>
#include "BinarySearch.h"
using namespace std;

#if 0

template<typename T>
void insertionSort(vector<T> &arr) {
    for (size_t begin = 1; begin < arr.size(); begin++) {
        int end = begin;
        //如果end元素小于end-1元素就交换位置,否则就跳出循环
        while (end > 0 && (arr[end] < arr[end - 1])) {
            swap(arr[end], arr[end - 1]);
            end--;
        }
    }
}

#elif 0

//优化,将交换改为挪动
template<typename T>
void insertionSort(vector<T> &arr) {
    for (size_t begin = 1; begin < arr.size(); begin++) {
        int end = begin;
        T value = arr[end];
        //如果end元素小于end-1元素就用end-1元素覆盖end元素,否则就跳出循环
        while (end > 0 && (value < arr[end - 1])) {
            arr[end] = arr[end - 1];
            end--;
        }
        arr[end] = value;
    }
}

#else

//对已排序部分进行二分搜索优化(在挪动的基础上再优化比较次数)
template<typename T>
void insertionSort(vector<T> &arr) {
    for (size_t begin = 1; begin < arr.size(); begin++) {
        T value = arr[begin]; //保存要插入的值
        int index = indexOfInsertion(arr, begin, value); //得到待插入位置
        //移动元素
        for (int i = begin; i > index; i--) {
            arr[i] = arr[i - 1];
        }
        arr[index] = value;
    }
}

#endif

#endif /* SRC_INSERTIONSORT_H_ */

堆排序

/*
 * HeapSort.h
 * 堆排序
 *  Created on: 2020年2月10日
 *      Author: LuYonglei
 */

#ifndef SRC_HEAPSORT_H_
#define SRC_HEAPSORT_H_
#include <vector>
using namespace std;

template<typename T>
void siftDown(vector<T> &arr, int index, int heapSize) {
    //下滤
    T element = arr[index]; //保存父节点的元素
    int half = heapSize / 2;
    while (index < half) {
        //index必须是叶子节点
        int childIndex = 2 * index + 1; //默认是左子节点
        T childElement = arr[childIndex]; //左子节点的元素
        int rightIndex = childIndex + 1; //右子节点下标
        //若右子节点的元素大于左子节点的元素,
        if (rightIndex < heapSize && arr[rightIndex] > childElement) {
            childElement = arr[rightIndex];
            childIndex = rightIndex;
        }
        //如果大于等于子节点,就跳出循环
        if (element >= childElement)
            break;
        //如果父节点元素小于子节点元素,用子节点元素覆盖父节点元素
        arr[index] = childElement;
        index = childIndex;
    }
    arr[index] = element;
}

//1.对序列原地建堆(heapify)
//2.
//  将0号元素与末尾元素交换位置
//  堆的size-1
//  对0号元素进行下滤(siftdown)
//  重复2中的以上操作,直至size变为1
template<typename T>
void heapSort(vector<T> &arr) {
    int heapSize = arr.size();
    //原地建堆,对所有元素进行下滤
    for (int i = heapSize / 2 - 1; i >= 0; i--)
        siftDown(arr, i, heapSize);
    while (heapSize > 1) {
        //交换堆顶元素和堆尾部元素,堆大小减小1
        swap(arr[0], arr[--heapSize]);
        //对堆顶元素进行下滤
        siftDown(arr, 0, heapSize);
    }
}

#endif /* SRC_HEAPSORT_H_ */

main函数

/*
 * main.cpp
 *
 *  Created on: 2020年2月10日
 *      Author: LuYonglei
 */

#include <iostream>
#include <vector>
#include "MyTemplate.h"
#include "BubbleSort.h"
#include "SelectionSort.h"
#include "HeapSort.h"
#include "InsertionSort.h"

using namespace std;

int main(int argc, char **argv) {
    vector<int> arr;
    int a[] = { 1, 2, 3, 6, 8, 19, 10, 3, 0, 0, 100, -1 };
    for (size_t i = 0; i < sizeof(a) / sizeof(int); i++)
        arr.push_back(a[i]);
//    bubbleSort(arr);
//    selectionSort(arr);
//    heapSort(arr);
    insertionSort(arr);
    print(arr);

}

猜你喜欢

转载自www.cnblogs.com/luyl/p/12294550.html