数据结构 — 基础排序

1.直接插入排序

 直接插入排序的思想:将数组的第一个元素就看为有序数组,然后从数组第二个数开始进行排序,将第二个数(将要进行比较排序的值)进行临时存储tmp),如果第一个数大于第二个数,那么就将较大的这个数往后挪动较小数继续往前比较,直到较小数碰到比自己更小的值(表找到自己在数组的位置),或比较到数组起始位置(表本次排序的数是最小值)即停止。

  • 时间复杂度:O(N^2)
  • 空间复杂度:O(1)
void InsertSort(int* a, int n)
{
    for (int i = 0; i < n-1; i++)//n-1防止越界比较
    {
        int end = i;
        int tmp = a[end + 1];
        while (end >= 0)//对比到最小位置
        {
            if (a[end] > tmp)
                a[end + 1] = a[end];//大的往后挪
            else
                break;
            end--;//下标--,只要a[end]比tmp大,就继续往前进行比较插入,直至比较到a[0]
        }
        a[end + 1] = tmp;//当比较到a[0],或者a[end] < tmp时,即代表tmp已经找到了自己对应的位置。
    }
}

请添加图片描述

2.希尔排序

 希尔排序本质上<直接插入排序>的pro plus max版,思想跟插排差不太多,但是在对数据的排序上却是快了很多,具体的行为就是对数据进行大量的预排序,到最后插入排序时效率非常高。

  • 时间复杂度:O(N^1.3)
  • 空间复杂度:O(1)
void ShellSort(int* a, int n)
{
    int gap = n;

    while (gap >= 1)
    {
        gap /= 2;

        for (int i = 0; i < n - gap; i++)//n-gap防止越界
        {
            int end = i;
            int tmp = a[end + gap];
            while (end >= 0)//依旧是判断到0
            {
                if (a[end] > tmp)
                    a[end + gap] = a[end];
                else
                    break;
                end -= gap;//这里不是end--,是end-gap步
            }
            a[end + gap] = tmp;
        }
    }
}

请添加图片描述

3.堆排序

 堆排序是利用堆这种数据结构的特性,堆数据进行快速的筛选,堆这种数据结构虽然不能使数组很快的进行排序成序,但堆阔以很快的找出数据中最大或者最小的数据以此进行排序。

  • 时间复杂度:O(N*logN)
  • 空间复杂度:O(1)
void AdjustDown(int* a,int n ,int parent)//
{
    int child = parent * 2 + 1;

    while (child < n)
    {
        if (child + 1 < n && a[child] < a[child + 1])//判断越界
            child++;

        if (a[parent] < a[child])
            Swap(&a[parent], &a[child]);

        parent = child;
        child = parent * 2 + 1;
    }
}

void HeapSort(int* a, int n)
{
    //建堆
    for (int i = (n-2)/2; i >= 0 ; i--)
    {
        AdjustDown(a, n, i);
    }

    int new_n = n - 1;
    while (new_n)
    {
        Swap(&a[new_n], &a[0]);
        AdjustDown(a, new_n--, 0);
      
    }
}

​​在这里插入图片描述


4.快速排序

 快速排序的基本思想就是选择数据中的中位数,然后利用双指针或者三指针进行快速对比交换排序

  • 时间复杂度:O(NlogN) ~O(NN)
  • 空间复杂度:O(1)
//双指针法 horel
int Par1(int* a, int left, int right)
{
    int key_i = left;
    while (left < right)
    {
        while (left < right && a[right] >= a[key_i])
            right--;
       
        while (left < right && a[left] <= a[key_i])
            left++;
    
        Swap(&a[left], &a[right]);
    }
   
    Swap(&a[left], &a[key_i]);

    return left;
}

//双指针前后
int Par2(int* a, int left, int right)
{
    int key_i = left;
    int pre = key_i;//尾随cur把大的往后甩
    int cur = key_i + 1;//cur负责赵小
    while (cur <= right)
    {
        if (a[cur] < a[key_i] && ++pre != cur)
            Swap(&a[cur], &a[pre]);
        cur++;
    }
    Swap(&a[key_i], &a[pre]);
    return pre;
}


//处理重复数据的快排
void QucikSort_repeatdate(int* a, int left, int right)
{
    if (left >= right)
        return;

    //随机选数
    int randi = left + (rand() % (right - left));
    if (randi != left)
    {
        Swap(&a[randi], &a[left]);//以左边做关键值
    }

    int begin = left;
    int end = right;//保存 起始结点 和 尾结点
    int keyi = a[left];
    int cur = left + 1;

    while (cur <= right)
    {
        if (a[cur] < keyi)
        {
            Swap(&a[cur], &a[left]);
            left++;
            cur++;
        }
        else if (a[cur] > keyi)
        {
            Swap(&a[cur], &a[right]);
            right--;
        }
        else
            cur++;

    }

    //所有相等的数据都在中间部位了
    QucikSort(a, begin, left - 1);//递归左区间
    QucikSort(a, right + 1, end);//递归右区间
}

void QuickSort(int* a, int left, int right)
{
    if (left >= right)
        return;

    int middle_i = Par2(a, left, right);
    QuickSort(a, left, middle_i - 1);
    QuickSort(a,  middle_i + 1,right);

}

这是一趟快速排序


5.归并排序

  归并递归的思想是,将所有元素分割到最小单位,当元素都是单个时,此时可以认为单个元素是有序的,然后进行壹壹归,之后进行贰贰归、肆肆归(2的倍数)。。。。以此类推最后将所有元素归并为有序。归并的整个过程是比较大小后进行尾插。归并排序之前写过点击归并排序即可。

  • 时间复杂度:O(N*logN) )
  • 空间复杂度:O(N)
    在这里插入图片描述

6.计数排序(数据映射类排序)

 计数排序对于数据范围集中的整形类数据排序速度很快,是一种映射类排序,但是排序出的数据并不是原始数据,只是对原始数据进行的一种复制排序。

//计数排序
void CountSort(int* a, int n)
{
	int min = a[0];
	int max = a[0];

	for (int i = 0; i < n; i++)
	{
		if (a[i] < min)
			min = a[i];
		if (a[i] > max)
			max = a[i];
	}

	int range = max - min + 1;
	int* count = (int*)calloc(range,sizeof(int));
	if (NULL == count)
	{
		perror("mlc fail\n");
		exit(-1);
	}
		
	//统计数据出现次数
	for (int i = 0; i < n; i++)
	{
		count[a[i] - min]++;
	}

	//排序复写数据
	int j = 0;
	for (int i = 0; i < range; i++)
	{
		while (count[i]--)
		{
			a[j++] = i + min;
		}
	}
}

7.选择排序和冒泡排序

 选择排序只推荐用来浅浅的了解一下,选择排序性能其实很一般,跟冒泡排序一个等级。

void SelectSort(int* a, int n)
{
	int begin = 0, end = n - 1;

	while (begin < end)
	{
		int mini = begin, maxi = begin;

		for (int i = begin + 1; i <= end; i++)
		{
			if (a[i] > a[maxi])//选出最小的
				maxi = i;

			if (a[i] < a[mini])//先出最大的
				mini = i;
		}
		
		Swap(&a[begin], &a[mini]);
		if (maxi == begin) maxi = mini;//修正maxi,避免begin就是最大值的情况。
		
		Swap(&a[end], &a[maxi]);

		++begin;
		--end;
	}
}


void BubbleSort(int* a, int n)
{
    int flag = 1;
    for (int i = 0; i < n-1; i++)
    {
        flag = 1;                         //-1是为了防止越界             
        for (size_t j = 0; j < n-i-1; j++)//不-1,第一趟就会越界,n-i(0) = n,第一趟最后比较就是n-1和n的数据比较,但是n位置就是越界了。
        {
            if (a[j] > a[j + 1])
            {
                Swap(&a[j], &a[j + 1]);
                flag = 0;
            }
        }
        if (1 == flag)
            break;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值