cen's blog cen's blog
首页
  • 编程文章

    • markdown使用
  • 学习笔记

    • 《JavaScript教程》
    • C++学习
    • C++数据结构
    • MySQL
    • Linux
  • 高中时代
  • 工作日常
  • CLion
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 分类
  • 标签
  • 归档
关于
GitHub (opens new window)

cen

十年饮冰,难凉热血
首页
  • 编程文章

    • markdown使用
  • 学习笔记

    • 《JavaScript教程》
    • C++学习
    • C++数据结构
    • MySQL
    • Linux
  • 高中时代
  • 工作日常
  • CLion
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 分类
  • 标签
  • 归档
关于
GitHub (opens new window)
  • 链表
  • 栈和队列
  • 二叉树
  • 堆
  • 排序
    • 插入排序
      • 直接插入排序
      • 希尔排序
    • 选择排序
      • 选择排序
      • 堆排序
    • 交换排序
      • 冒泡排序
      • 快速排序
    • 归并排序
    • 计数排序
    • 总结
  • 搜索二叉树
  • 平衡二叉树
  • 红黑树
  • 哈希表
  • C++数据结构
cen
2025-01-22
目录

排序

排序算法的可视化 (opens new window)

# 插入排序

# 直接插入排序

直接插入排序

void InsertSort() {  
    if (nums.size() <= 1)  
        return;  
    for (int i = 1; i < nums.size(); i++) {  
        int j = i;  
        // 因为前面已经有序  
        while (j >= 0 && nums[j] < nums[j - 1]) {  
            swap(nums[j], nums[j - 1]);  
            j--;  
        }    
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

# 希尔排序

对直接插入排序的优化

  1. 预排序:按照一个间距gap进行排序
  2. 直接插入排序

gap越大,前面大的数可以越快到后面,后面小的数可以越快到前面,越不接近有序。

希尔排序

void ShellSort() {  
    int gap = nums.size();  
    while (gap > 0) {  
        gap /= 2;  
        for (int i = 0; i < nums.size(); i++) {  
            int j = i;  
            while (j - gap >= 0 && nums[j] < nums[j - gap]) {  
                swap(nums[j], nums[j - gap]);  
                j -= gap;  
            }        
        }    
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 选择排序

# 选择排序

  • 每次从待排序列中选出一个最小值,然后放在序列的起始位置,直到全部待排数据排完即可。
void SelectSort_single() {  
    for (int i = 0; i < nums.size(); i++) {  
        int min = i;  
        for (int j = i; j < nums.size(); j++) {  
            if (nums[j] < nums[min]) {  
                min = j;  
            }        
        }        
        swap(nums[i], nums[min]);  
    }
}
1
2
3
4
5
6
7
8
9
10
11
  • 为了提高效率,每次从待排序列中选出一个最小值和一个最大值,直到全部待排数据排完即可。
void SelectSort_double() {  
    int min = 0;  
    int max = nums.size() - 1;  
    while (min < max) {  
        int minindex = min;  
        int maxindex = min;  
        for (int i = min; i <= max; i++) {  
            if (nums[minindex] > nums[i])  
                minindex = i;  
            if (nums[maxindex] < nums[i])  
                maxindex = i;  
        }        
        swap(nums[maxindex], nums[max]);  
        if (min == maxindex) {  
            maxindex = minindex;  
        }        
        swap(nums[minindex], nums[min]);  
        min++;  
        max--;  
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 堆排序

// 堆:下滤操作(大根堆)
void Down(int root) {
    int parent = root;
    int child = 2 * parent + 1;
    // 默认左孩子为较大值
    while (child < nums.size()) {
        if (child + 1 < nums.size() && nums[child] < nums[child + 1])
            child++;
        if (nums[parent] < nums[child]) {
            swap(nums[parent], nums[child]);
            parent = child;
            child = 2 * parent + 1;
        } else {
            break;
        }
    }
}

// 堆排序(升序:建立大根堆)
void HeapSort() {
    for (int i = (int) ((nums.size() - 1) / 2); i >= 0; i--) {
        Down(i);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 交换排序

# 冒泡排序

void BubbleSort() {  
    bool flag = true;  
    for (int i = 0; i < nums.size() - 1; i++) {  
        for (int j = 0; j < nums.size() - 1 - i; j++) {  
            if (nums[j] > nums[j + 1]) {  
                swap(nums[j], nums[j + 1]);  
                flag = false;  
            }        
        }        
        if (flag)  
            break;  
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 快速排序

  • Hoare法: Hoare版本的单趟排序的基本步骤如下:
  1. 选出一个pivot,一般是最左边或是最右边的。
  2. 定义一个L和一个R,L从左向右走,R从右向左走。(若选择最左边的数据作为pivot,则需要R先走;若选择最右边的数据作为pivot,则需要L先走)。
  3. 在走的过程中,若R遇到小于pivot的数,则停下,L开始走,直到L遇到一个大于pivot的数时,将L和R的内容交换,R再次开始走,如此进行下去,直到L和R最终相遇,此时将相遇点的内容与pivot交换即可。

快排

// Hoare法  
int PartSort(int left, int right) {  
    int start = left;  
    int pivot = nums[left];  
    while (left < right) {  
        while (left < right && nums[right] >= pivot)  
            right--;  
        while (left < right && nums[left] <= pivot)  
            left++;  
        if(left < right)  
            swap(nums[left++],nums[right--]);  
    }    
    swap(nums[start],nums[left]);  
    return left;  
}  
  
// 快速排序(以nums[0]为pivot)  
void QuickSort(int left, int right) {  
    if (left < right) {  
        int index = PartSort(left, right);  
        QuickSort(left, index - 1);  
        QuickSort(index + 1, right);  
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  • 坑位法:
  1. 选出一个数据(一般是最左边或是最右边的)作为pivot,在该数据位置形成一个坑。
  2. 还是定义一个L和一个R,L从左向右走,R从右向左走。
  3. 在走的过程中,若R遇到小于pivot的数,则将该数抛入坑位,并在此处形成一个坑位,这时L再向后走,若遇到大于pivot的数,则将其抛入坑位,又形成一个坑位,如此循环下去,直到最终L和R相遇,这时将pivot抛入坑位即可。

快排

// 坑位法  
int PartSort(int left, int right) {  
    int pivot = nums[left];  
    while (left < right) {  
        while (left < right && nums[right] >= pivot)  
            right--;  
        nums[left] = nums[right];  
        while (left < right && nums[left] <= pivot)  
            left++;  
        nums[right] = nums[left];  
    }    
    nums[left] = pivot;  
    return left;  
}  
  
// 快速排序(以nums[0]为pivot)  
void QuickSort(int left, int right) {  
    if (left < right) {  
        int index = PartSort(left, right);  
        QuickSort(left, index - 1);  
        QuickSort(index + 1, right);  
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  • 快速排序的优化:
// 坑位法
int QuickPartSort(int left, int right) {
    int pivot = nums[left];
    while (left < right) {
        while (left < right && nums[right] > pivot)
            right--;
        nums[left] = nums[right];
        while (left < right && nums[left] < pivot)
            left++;
        nums[right] = nums[left];
    }
    nums[left] = pivot;
    return left;
}

//三数取中
int GetMidIndex(int left, int right) {
    int mid = left + (right - left) / 2;
    if (nums[mid] > nums[left]) {
        if (nums[mid] < nums[right])
            return mid;
        else if (nums[left] > nums[right])
            return left;
        else
            return right;
    } else {
        if (nums[mid] > nums[right])
            return mid;
        else if (nums[left] > nums[right])
            return right;
        else
            return left;
    }
}

// 快速排序(以nums[0]为pivot)
void QuickSort(int left, int right) {
    if (left < right) {
        int midindex = GetMidIndex(left,right);
        swap(nums[midindex],nums[left]);
        int index = QuickPartSort(left, right);
        QuickSort(left, index - 1);
        QuickSort(index + 1, right);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

# 归并排序

归并排序

void MergePartSort(int left, int right, vector<int> &temp) {
    if (left >= right)
        return;
    int i = left;
    // 分割
    int mid = left + (right - left) / 2;    // 防止整型溢出
    MergePartSort(left, mid, temp);
    MergePartSort(mid + 1, right, temp);
    // 合并
    int begin1 = left, end1 = mid;
    int begin2 = mid + 1, end2 = right;
    while (begin1 <= end1 && begin2 <= end2) {
        if (nums[begin1] < nums[begin2])
            temp[i++] = nums[begin1++];
        else
            temp[i++] = nums[begin2++];
    }
    while (begin1 <= end1)
        temp[i++] = nums[begin1++];
    while (begin2 <= end2)
        temp[i++] = nums[begin2++];
    // 将临时数组中的排序结果复制回原数组
    for (int j = left; j <= right; ++j) {
        nums[j] = temp[j];
    }
}

// 归并排序
void MergeSort(int left, int right) {
    vector<int> temp(right + 1);
    MergePartSort(left, right, temp);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# 计数排序

// 计数排序  
void CountSort() {  
    int max = INT_MIN;  
    int min = INT_MAX;  
    for (int i: nums) {  
        if (i > max)  
            max = i;  
        if (i < min)  
            min = i;  
    }    vector<int> Countarr(max - min + 1);  
    for (int i: nums) {  
        Countarr[i - min]++;  
    }    int index = 0;  
    for (int i = 0; i < Countarr.size(); i++) {  
        while (Countarr[i] > 0) {  
            nums[index++] = i + min;  
            Countarr[i]--;  
        }    
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 总结

排序方法 平均情况 最好情况 最坏情况 辅助空间 稳定性
插入排序 O(n2) O(n) O(n2) O(1) 稳定
希尔排序 O(nlogn)~O(n2) O(n1.3) O(n2) O(1) 不稳定
选择排序 O(n2) O(n2) O(n2) O(1) 不稳定
堆排序 O(nlogn) O(nlogn) O(nlogn) O(1) 不稳定
冒泡排序 O(n2) O(n) O(n2) O(1) 稳定
快速排序 O(nlogn) O(nlogn) O(n2) O(logn)~O(n) 不稳定
归并排序 O(nlogn) O(nlogn) O(nlogn) O(n) 稳定

# from cen


上次更新: 2025/01/22, 20:13:47
堆
搜索二叉树

← 堆 搜索二叉树→

最近更新
01
线程安全
05-21
02
cmake教程
05-08
03
项目
05-07
更多文章>
Theme by Vdoing | Copyright © 2024-2025 京ICP备2020044002号-3 京公网安备11010502056119号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式