#include <list>
#include <vector>
#include <set>
#include <deque>
#include <sys/time.h>
#include <unistd.h>
#include <sys/timeb.h>
#include <thread>
#include <iostream>
//g++ -Wl,-as-needed -std=c++11 -o sort sort.cpp
void swap(int& n1, int& n2)
{
int tmp = n1;
n1 = n2;
n2 = tmp;
}
void print_data(int data[], int n)
{
for (size_t i = 0; i < n; i++)
{
printf("%d, ", data[i]);
}
printf("\n");
}
//以下都按升序排序
//冒泡排序
void maopao_sort(int data[], int n)
{
//思想:相邻两个比较大小,大的往后冒,直到后面得到当前无序序列的最大值
//有序序列保存在后部分
//每冒泡一趟得到一个最值,然后append一个到有序序列的head位置
//外层循环控制冒泡得到的有序序列不再参与冒泡
//内层循环控制在无序序列中不断的冒泡
//每一趟在不满足既定的大小关系时都需要交换位置
for (size_t i = n; i > 0; --i)
{
for (size_t j = 1; j < i; ++j)
{
if(data[j-1] > data[j])
{
swap(data[j-1], data[j]);
}
}
}
}
//插入排序
void insert_sort(int data[], int n)
{
//思想:主动和面前的人对比然后交换位置直到定位好自己为止
//有序序列保存在前部分
//外层循环保证每一个都能有自主寻找位置的机会
//内层循环控制它只能在已经确定好了位置的有序序列中查找自己的位置
//默认第一个是排好序的,从第1个开始执行
//在找到自己的位置前每次比较都需要执行位置交换。 和冒泡不一样的是它是在有序序列不断地交换位置
for (size_t i = 1; i < n; ++i)
{
for (size_t j = i; j >= 0; --j)
{
if(data[j] > data[j-1])
{
break;
}
swap(data[j-1], data[j]);
}
}
}
//选择排序
void select_sort(int data[], int n)
{
//思想:从当前无序序列中查找到最小值的index,然后把这个最小值append到有序序列的tail位置
//算是冒泡的一种改进,记录index位置,避免了冒泡中每次都可能交换位置的消耗,所以性能比冒泡好
//有序序列保存在前部分
for (size_t i = 0; i < n; ++i)
{
int min = i;
for (size_t j = i+1; j < n; ++j)
{
if(data[j] < data[min] )
{
min = j;
}
}
swap(data[i], data[min]);
}
}
//快速排序
void quick_sort(int data[], int i, int j)
{
//思想:相当于2分法,分而治之。从序列中找一个作为key,以key为界限,一趟之后左边比key大,右边比base小,然后对左右两个序列以递归方式再分而治之,最终分到不可再分时就完成了排序
if(i >= j){//不可再划分
return;
}
int start = i;
int end = j;
//以第一个为key
int key = data[i];
int key_index = i;
printf("begin, i:%d, j:%d, key:%d\n", i, j, key);
//控制两头能不断继续前行进行比较
while (i < j)
{
printf("while data[%d]:%d, data[%d]:%d, key:%d\n", i, data[i], j, data[j], key);
//从右端开始往左前行,直到找到比key小的为止
while (i < j && data[j] >= key)
{
//printf("right find data[%d]:%d < key:%d\n", j, data[j], key);
--j;
}
//把小的都移到key的左边。因为第i个已经保存到key中了,所以可以直接把小的覆盖在i位置上。
//在i<j的条件中执行--j,所以j可能会等于i,所以判断只有i<j的时候才交换位置
if(i < j){
data[i] = data[j];
}
//左边往右前行,寻找比key大的交换到key的右边
while (i < j && data[i] <= key)
{
//printf("left find data[%d]:%d > key:%d\n", i, data[i], key);
++i;
}
//j位置已经把数据移到了i位置,所以i位置的可以直接覆盖到j位置
if(i < j){
data[j] = data[i];
}
}
//走一趟之后,在i的右边都是j走过的路,都是大于key的值。i的左边都是i走过的路,都是小于key的值。这个时候 i==j ,如果j是找到了小于key的值后停下来的话,j的数据已经移走,空出了j的位置,这时可以直接把可以赋在j位置。如果j是没找到移动的数据,那就是j在走的时候遇到了i所以停了下来,这个时候i的数据是初始化时就赋给key了,这个时候还是可以再把key赋值回来。所以在i遇到j的时候无论是哪一种情况都可以把key赋值给i,这样i的左右两边都满足了排序的规则。
data[i] = key;
//print_data(data, 22);
//继续递归左右两边序列
{
if(i > start+1){
printf("quick_sort1, start:%d, i:%d, j:%d, end:%d\n", start, i, j, end);
quick_sort(data, start, i-1);
}
if(end > j + 1){
printf("quick_sort2, start:%d, i:%d, j:%d, end:%d\n", start, i, j, end);
quick_sort(data, j+1, end);
}
}
}
//堆排序——堆调整
void heap_adjust(int data[], int n, int i)
{
//从后往前见大顶堆,3个值为一树
//找出i的左右孩子
int left = 2 * i + 1;
//需要判断下left和right的合法性,因为left和right是计算出来的,有可能已经超出了n,即这个i不存在子节点
if(left > n-1){
//printf("parent:%d, left:%d, n:%d\n", i, left, n);
return;
}
int child = left;
int right = 2 * i + 2;
if(right <= n-1 && data[right] > data[left]){//比较左右孩子谁大,取大的和parent进行调整
child = right;
}
printf("parent:%d-%d, child:%d-%d\n", i, data[i], child, data[child]);
//选择大的孩子同parent比较,parent大的话什么也不用做,parent小的话较好child和parent的位置
if(data[i] > data[child]){
return;
}
swap(data[i], data[child]);
//因为是从child往parent方向建堆,所以parent调整下来之后child的child可能就不是堆了,所以需要继续调整child的堆,递归调整完就结束
heap_adjust(data, n, child);
}
//堆排序——创建大顶堆
void create_heap(int data[], int n)
{
//从最后一个parent开始,每个parent都执行一次堆调整。
for(int i = n / 2 - 1; i >= 0; --i){
heap_adjust(data, n, i);
}
}
//堆排序
void heap_sort(int data[], int n)
{
create_heap(data, n);
print_data(data, n);
//原理:不断地从当前大顶堆中选最大值放到数组后面进行排序。
//建大顶堆的目的就是为了从堆中快速选择最大值,相当于是选择排序的一种改进。选自排序是从头到尾遍历寻找最值来append到有序序列中,这种为找最值遍历的次数多。
//为了缩小遍历次数建立了堆,堆的遍历次数只是堆的高度,所以遍历的次数会少很多,效率也就高很多了
//控制有序序列和无序序列的临界区。每排序一次,有序序列会多一个,无序序列会少一个,直到无序序列为0个排序结束
//刚开始全是无序,但知道第0个是最大值,需要对数组的每一个都做一次最值选择,从第0个开始
for(int i = n-1; i >= 0; --i)
{
//把当前最大值放到当前有序序列before位置
swap(data[i], data[0]);
//交换之后需要对剩下的进行堆调整
heap_adjust(data, i, 0);
}
}
int main()
{
int data[] = {12,34,67,8,12,9842,789,23,978,3,10000,234,56,78,243,423,34,243,43,6785,312,1};
//maopao_sort(data, sizeof(data)/sizeof(data[0]));
//insert_sort(data, sizeof(data)/sizeof(data[0]));
//select_sort(data, sizeof(data)/sizeof(data[0]));
//quick_sort(data, 0, sizeof(data)/sizeof(data[0])-1);
heap_sort(data, sizeof(data)/sizeof(data[0]));
print_data(data, sizeof(data)/sizeof(data[0]));
return 0;
}
常见排序算法
最新推荐文章于 2025-07-22 22:07:53 发布