排序算法汇总(C/C++实现)

 一、冒泡排序

1.简介

        冒泡排序是计算机科学中最简单的排序算法之一,它重复地遍历要排序的元素,比较每对相邻项,如果它们的顺序错误就将它们交换过来。经过一轮的遍历,最大(或最小)的元素就会“冒泡”到顶端(或底端),然后在下一轮中继续这个过程。这个过程持续进行直到所有的元素都排好序为止。

2.代码
int bubble_sort(int* data, int length) {
    // 外层循环控制轮数,每轮确定一个最大元素的位置
    for (int i = 0; i < length; ++i) {
        // 内层循环遍历未排序部分的相邻元素,进行比较和交换
        for (int j = 0; j < length - i - 1; ++j) {
            // 如果相邻元素顺序错误,则进行交换
            if (data[j] > data[j + 1]) {
                // 交换相邻元素的值
                int temp = data[j];
                data[j] = data[j + 1];
                data[j + 1] = temp;
            }
        }
    }
    return 0;
}
3.其他分析

平均时间复杂度:O(n*n)    最好情况:O(n)    最坏情况:O(n*n)

空间复杂度:O(1)    排序方式:内排序    稳定性:稳定

 二、选择排序

1.简介

        选择排序是一种简单直观的排序算法,它的基本思想是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。

2.代码
// 定义选择排序函数,参数为待排序数组和数组长度
int selection_sort(int* data, int length) {
    // 外层循环遍历数组,每次确定一个最小值的位置
    for (int i = 0; i < length - 1; ++i) {
        // 假设当前位置为最小值的位置
        int minIndex = i;
        // 内层循环遍历未排序部分,查找最小值的位置
        for (int j = i + 1; j < length; ++j) {
            // 如果当前元素比最小值还小,则更新最小值的位置
            if (data[j] < data[minIndex]) {
                minIndex = j;
            }
        }
        // 将当前最小值与当前轮次第一个位置的元素交换
        int temp = data[i];
        data[i] = data[minIndex];
        data[minIndex] = temp;
    }
    return 0; // 返回排序完成标志
}
3.其他分析

平均时间复杂度:O(n*n)    最好情况:O(n*n)    最坏情况:O(n*n)

空间复杂度:O(1)    排序方式:内排序    稳定性:不稳定

三、插入排序

1.简介

        插入排序的核心思想是逐步构建有序序列。在遍历未排序部分的元素时,将每个元素插入到已排序序列的合适位置,从而逐步扩大已排序序列的范围,最终使整个序列有序。

2.代码
int insertion_sort(int* data, int length) {
    // 从第二个元素开始遍历,因为第一个元素默认为已排序的序列
    for (int i = 1; i < length; ++i) {
        // 将当前元素保存为 key
        int key = data[i];
        // 从已排序的序列末尾开始向前查找要插入的位置
        int j = i - 1;
        // 在已排序的序列中寻找插入位置,并将比 key 大的元素后移
        while (j >= 0 && data[j] > key) {
            data[j + 1] = data[j]; // 后移元素
            --j; // 向前查找
        }
        // 将 key 插入到合适的位置
        data[j + 1] = key;
    }
    return 0;
}
3.其他分析

平均时间复杂度:O(n*n)    最好情况:O(n)    最坏情况:O(n*n)

空间复杂度:O(1)    排序方式:内排序    稳定性:稳定

四、希尔排序

1.简介

        希尔排序是一种插入排序的改进版本,它的基本思想是将数组分成若干个子序列,对每个子序列进行插入排序,然后逐步缩小子序列的间隔,直至间隔为1,最后进行一次完整的插入排序。

2.代码
int shell_sort(int* data, int length) {
    // 遍历增量序列,初始增量为数组长度的一半,逐步缩小增量直至为1
    for (int gap = length / 2; gap > 0; gap /= 2) {
        // 对每个子序列进行插入排序
        for (int i = gap; i < length; ++i) {
            int temp = data[i]; // 保存当前值,以便后续插入
            int j = i; // 初始化插入位置为当前位置
            // 插入排序,将大于temp的元素向后移动
            while (j >= gap && data[j - gap] > temp) {
                data[j] = data[j - gap]; // 向后移动元素
                j -= gap; // 向前移动插入位置
            }
            data[j] = temp; // 插入temp到合适位置
        }
    }
    return 0; // 排序完成
}
3.其他分析

平均时间复杂度:O(n*1.3)    最好情况:O(n)    最坏情况:O(n*n)

空间复杂度:O(1)    排序方式:内排序    稳定性:不稳定

五、归并排序

1.简介

        归并排序是一种分治算法,其基本思想是将原始数组分成若干个较小的子数组,分别对子数组进行排序,然后再将排好序的子数组合并成一个整体有序的数组。具体步骤如下:

        (1)分解:将原始数组分成两个较小的子数组,直到子数组的大小为1。

        (2)排序:对每个子数组进行排序。

        (3)合并:将两个有序的子数组合并成一个整体有序的数组。

2.代码
// 归并排序算法,对数组data的[left, right]范围进行排序
int merge_sort(int* data, int left, int right) {
    // 当左边界小于右边界时,进行递归排序
    if (left < right) {
        // 计算中间位置,使用这种方式计算防止整数过大时溢出
        int middle = left + (right - left) / 2;
        // 递归排序左半部分
        merge_sort(data, left, middle);
        // 递归排序右半部分
        merge_sort(data, middle + 1, right);
        // 合并左右两部分有序数组
        merge_arr(data, left, middle, right);
    }
    return 0;
}

// 合并两个有序数组
void merge_arr(int* data, int left, int middle, int right) {
    // 计算左右两个数组的长度
    int left_arr_length = middle - left + 1;
    int right_arr_length = right - middle;
    // 创建临时数组存放左右两个有序数组
    int left_arr[left_arr_length];
    int right_arr[right_arr_length];

    // 将左边界到中间位置的元素复制到左边数组
    for (int i = 0; i < left_arr_length; ++i) {
        left_arr[i] = data[left + i];
    }

    // 将中间位置+1到右边界的元素复制到右边数组
    for (int i = 0; i < right_arr_length; ++i) {
        right_arr[i] = data[middle + i + 1];
    }

    // 合并两个有序数组
    int i = 0, j = 0, k = left;
    while (i < left_arr_length && j < right_arr_length) {
        // 比较左右两个数组当前位置的元素,将较小的元素放入原数组
        if (left_arr[i] <= right_arr[j]) {
            data[k] = left_arr[i];
            i++;
        } else {
            data[k] = right_arr[j];
            j++;
        }
        k++;
    }

    // 将剩余的元素依次放入原数组
    while (i < left_arr_length) {
        data[k] = left_arr[i];
        i++;
        k++;
    }

    while (j < right_arr_length) {
        data[k] = right_arr[j];
        j++;
        k++;
    }
}
3.其他分析

平均时间复杂度:O(nlogn)    最好情况:O(nlogn)    最坏情况:O(nlogn)

空间复杂度:O(n)    排序方式:外排序    稳定性:稳定

六、快速排序

1.简介

        快速排序(Quick Sort)是一种常见的高效排序算法,基于分治思想。其思想是选择一个基准元素,然后将数组分成两部分,左边部分的元素都小于基准元素,右边部分的元素都大于基准元素,然后递归地对左右两部分进行快速排序。

2.代码
// 交换两个元素的值
void swap(int* first, int* second) {
    int temp = *first;
    *first = *second;
    *second = temp;
}

// 快速排序递归函数
int quick_sort(int* data, int left, int right) {
    if (left < right) {
        // 找到基准元素的位置
        int pivot = findPivot(data, left, right);
        // 对左右两部分进行快速排序
        quick_sort(data, left, pivot - 1);
        quick_sort(data, pivot + 1, right);
    }
    return 0;
}

// 找到基准元素的位置,并将数组划分为左右两部分
int findPivot(int* data, int left, int right) {
    // 选择最后一个元素作为基准元素
    int pivot = data[right];
    // 定义左右指针
    int i = left - 1; // 左指针
    // 将小于基准元素的放在左边,大于等于基准元素的放在右边
    for (int j = left; j < right; ++j) {
        if (data[j] < pivot) {
            // 如果当前元素小于基准元素,交换位置
            ++i;
            swap(&data[i], &data[j]);
        }
    }
    // 将基准元素放在正确的位置
    swap(&data[i + 1], &data[right]);
    // 返回基准元素的位置
    return i + 1;
}
3.其他分析

平均时间复杂度:O(nlogn)    最好情况:O(nlogn)    最坏情况:O(n*n)

空间复杂度:O(logn)    排序方式:内排序    稳定性:不稳定

七、堆排序

1.简介

        堆排序是一种高效的排序算法,其基本思想是利用堆这种数据结构进行排序。堆是一种特殊的完全二叉树,满足堆的性质:对于每个节点 i,父节点的值大于等于(或小于等于)其子节点的值。堆排序的基本步骤如下:

(1)将待排序序列构建成一个大顶堆(或小顶堆)。

(2)将堆顶元素(最大值或最小值)与堆末尾元素进行交换,然后重新调整堆,使其满足堆的性质。

(3)重复步骤 2,直到堆中只剩下一个元素,此时序列已经有序。

2.代码
void heap_sort(int *data, int length) {
    // 构建最大堆
    for (int i = length / 2 - 1; i >= 0; --i) {
        heapify(data, length, i);
    }
    // 从最后一个节点开始,逐个将最大元素移到末尾,然后重新调整堆
    for (int i = length - 1; i > 0; --i) {
        // 将堆顶元素(最大元素)与当前未排序部分的末尾元素交换
        heap_swap(&data[0], &data[i]);
        // 对剩余部分重新进行堆化,保持最大堆性质
        heapify(data, i, 0);
    }
}

void heapify(int *data, int length, int currentIndex) {
    int largest = currentIndex; // 当前节点索引
    int left_node = 2 * currentIndex + 1; // 左子节点索引
    int right_node = 2 * currentIndex + 2; // 右子节点索引
    
    // 如果左子节点存在且大于当前节点,则更新最大值索引
    if (left_node < length && data[left_node] > data[largest]) {
        largest = left_node;
    }
    // 如果右子节点存在且大于当前节点,则更新最大值索引
    if (right_node < length && data[right_node] > data[largest]) {
        largest = right_node;
    }
    
    // 如果最大值索引不等于当前节点索引,说明需要调整堆
    if (largest != currentIndex) {
        // 将当前节点与最大值节点交换
        heap_swap(&data[currentIndex], &data[largest]);
        // 对以最大值节点为根的子树继续进行堆化
        heapify(data, length, largest);
    }
}

void heap_swap(int* first, int* second) {
    int temp = *first;
    *first = *second;
    *second = temp;
}
3.其他分析

平均时间复杂度:O(nlogn)    最好情况:O(nlogn)    最坏情况:O(nlogn)

空间复杂度:O(1)    排序方式:内排序    稳定性:不稳定

八、计数排序

1.简介

        计数排序(Counting Sort)是一种非比较排序算法,适用于排序一定范围内的整数。其基本思想是通过统计每个元素出现的次数,然后根据元素的值和出现次数重新构建有序序列。

2.代码
void counting_sort(int* data, int length) {
    // 找到数组中的最大值和最小值
    int max_val = data[length - 1];
    int min_val = data[length - 1];
    for (int i = 0; i < length; ++i) {
        if (data[i] > max_val) {
            max_val = data[i];
        }
        if (data[i] < min_val) {
            min_val = data[i];
        }
    }

    // 计算计数数组的大小
    int count_size = max_val - min_val + 1;
    // 初始化计数数组为0
    int count[count_size];
    for (int i = 0; i < count_size; ++i) {
        count[i] = 0;
    }

    // 统计每个元素出现的次数
    for (int i = 0; i < length; ++i) {
        int index = data[i] - min_val;
        count[index] = count[index] + 1;
    }

    // 将计数数组中的元素依次填充回原数组
    int index = 0;
    for (int i = 0; i < count_size; ++i) {
        for (int j = 0; j < count[i]; ++j) {
            data[index++] = i + min_val;
        }
    }
}
3.其他分析

平均时间复杂度:O(n+k)    最好情况:O(n+k)    最坏情况:O(n+k)

空间复杂度:O(k)    排序方式:外排序    稳定性:稳定

九、桶排序

1.简介

        桶排序(Bucket Sort)是一种排序算法,它通过将数据分到有限数量的桶中,然后对每个桶中的数据进行排序,最后按照顺序将所有的桶中的数据合并起来。桶排序适用于待排序数据分布比较均匀的情况下。

2.代码
void bucket_sort(int* data, int length) {
    // 找到数组中的最大值和最小值
    int max_val = data[length - 1];
    int min_val = data[length - 1];
    for (int i = 0; i < length; ++i) {
        if (data[i] < min_val) {
            min_val = data[i];
        }
        if (data[i] > max_val) {
            max_val = data[i];
        }
    }

    // 计算桶的大小
    int bucket_size = (max_val - min_val) / length + 1;

    // 创建桶,初始化为-1
    int bucket[bucket_size][length];
    for (int i = 0; i < bucket_size; ++i) {
        for (int j = 0; j < length; ++j) {
            bucket[i][j] = -1;
        }
    }

    // 将元素分配到桶中
    for (int i = 0; i < length; ++i) {
        int bucket_index = (data[i] - min_val) / length;
        int j = 0;
        // 在桶中找到合适的位置存放元素
        while (bucket[bucket_index][j] != -1) {
            ++j;
        }
        bucket[bucket_index][j] = data[i];
    }

    // 对每个桶中的元素进行排序(这里使用冒泡排序)
    for (int i = 0; i < bucket_size; ++i) {
        for (int j = 0; j < length; ++j) {
            if (bucket[i][j] == -1) {
                break;
            }
            // 冒泡排序
            for (int k = 0; k < length - 1; ++k) {
                if ((bucket[i][k] > bucket[i][k + 1]) && (bucket[i][k + 1] != -1)) {
                    int temp = bucket[i][k];
                    bucket[i][k] = bucket[i][k + 1];
                    bucket[i][k + 1] = temp;
                }
            }
        }
    }

    // 将桶中的元素依次放回原数组中
    int index = 0;
    for (int i = 0; i < bucket_size; ++i) {
        for (int j = 0; j < length; ++j) {
            if (bucket[i][j] == -1) {
                break;
            }
            data[index++] = bucket[i][j];
        }
    }
}
3.其他分析

平均时间复杂度:O(n+k)    最好情况:O(n+k)    最坏情况:O(n*n)

空间复杂度:O(n + k)    排序方式:外排序    稳定性:稳定

十、基数排序

1.简介

        数排序是一种非比较性的排序算法,它根据元素的位数来对元素进行排序。基数排序的思想是从最低位开始,依次对各个位上的元素进行排序,直到最高位。每次排序过程都是稳定的,即在同一位上相同元素的相对顺序不会改变。基数排序可以应用于整数或字符串等数据类型。

2.代码
// 获取数字 num 的第 digit 位数字
int get_digit(int num, int digit) {
    return (num / (int)(pow(10, digit - 1))) % 10;
}

// 基数排序函数
void radix_sort(int* data, int length) {
    int bucket_size = 10;
    int bucket[10][length];

    // 初始化桶
    for (int i = 0; i < 10; ++i) {
        for (int j = 0; j < length; ++j) {
            bucket[i][j] = -1;
        }
    }

    // 获取数组中的最大值
    int max_val = data[length - 1];
    for (int i = 0; i < length; ++i) {
        if (data[i] > max_val) {
            max_val = data[i];
        }
    }

    // 获取最大值的位数
    int max_digit = 0;
    while (max_val > 0) {
        max_val /= 10;
        max_digit++;
    }

    // 按位进行排序
    for (int digit = 1; digit <= max_digit; ++digit) {
        // 分配过程:将数字放入对应的桶中
        for (int i = 0; i < length; ++i) {
            int bucket_index = get_digit(data[i], digit);
            int j = 0;
            int wait_insert = data[i];
            while (bucket[bucket_index][j] != -1) {
                if (wait_insert < bucket[bucket_index][j]) {
                    // 插入操作
                    int temp = bucket[bucket_index][j];
                    bucket[bucket_index][j] = wait_insert;
                    wait_insert = temp;
                }
                j++;
            }
            // 将待插入的元素放入桶中
            bucket[bucket_index][j] = wait_insert;
        }

        // 收集过程:将桶中的数字按顺序放回原数组中
        int index = 0;
        for (int i = 0; i < bucket_size; ++i) {
            for (int j = 0; j < length; ++j) {
                if (bucket[i][j] == -1) {
                    break;
                }
                data[index++] = bucket[i][j];
            }
        }

        // 清空桶
        for (int i = 0; i < 10; ++i) {
            for (int j = 0; j < length; ++j) {
                bucket[i][j] = -1;
            }
        }
    }
}
3.其他分析

平均时间复杂度:O(n*k)    最好情况:O(n*k)    最坏情况:O(n*k)

空间复杂度:O(n + k)    排序方式:外排序    稳定性:稳定

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值