排序算法学习

排序算法学习

做Leetcode977时,发现下面有人总结各种排序算法。故借这篇文章帮助自己学习&复习一下各种排序算法。

1.直接插入排序

1.1 算法图

图片引用自blog 链接: 【数据结构】插入排序 — 直接插入排序

Alt

1.2 算法步骤

  1. 将待排序的数组分为已排序区间和未排序区间,一开始已排序区间只有一个元素,即数组的第一个元素。
  2. 从未排序区间依次取出元素插入到已排序区间中。插入的方式是从已排序区间的最右侧开始比较,找到插入位置后将该位置右侧的元素全部向右移动一位,最后将待插入元素放入该位置。
  3. 重复步骤 2 直到未排序区间中的所有元素都被插入到已排序区间中,此时排序完成。

1.3 C语言实现

int* sortedSquares(int* nums, int numsSize, int* returnSize){
    int *back  = (int *)malloc(sizeof(int) * 10000);
    int temp;
    for (int i = 0; i < numsSize; i++) {
        temp = nums[i];
        for (int j = i - 1; j > 0; j--) {
            if (temp < nums[j]) {
                nums[j + 1] = nums[j];
            }
        }
        a[j+1] = temp;
    }
    *returnSize = numsSize;
    return back;
}

理解的难点在于如何理解下面这部分代码

 nums[j + 1] = nums[j];

这个if判断里的代码就是判断每次我们要进行挪动的量,是否大于其左边的每一个变量,如果大于,那么不需要挪动,如果小于,则把左边的变量进行移动。

2.折半插入排序(插入排序的升级版)

2.1 算法图

图片引用自blog 链接: 折半插入排序算法

Alt

2.2 算法步骤

基本同插入排序过程,只不过在每次选定要插入的元素时不每个进行比较,而是在需要插入的范围内进行二分查找。

2.3 C语言实现

int* sortedSquares(int* nums, int numsSize, int* returnSize){
    int *back  = (int *)malloc(sizeof(int) * 10000);
    int temp;
    for (int i = 0; i < numsSize; i++) {
        temp = nums[i];
        int low = 0;high = numsSize - 1;
        while (low <= high) {
        	int mid = (low + high) / 2;
        	if (temp > nums[mid]) {low = mid + 1;}
        	else high = mid - 1;
        }
        for (int j = i - 1; j > 0; j--) {
            if (temp < nums[j]) {
                nums[j + 1] = nums[j];
            }
        }
        a[j+1] = temp;
    }
    *returnSize = numsSize;
    return back;
    }

3.选择排序

3.1 算法图

图片引用自知乎 链接: 通俗易懂讲解 选择排序
Alt

3.2算法步骤

  1. 从待排序序列中,找到关键字最小的元素。
  2. 如果最小元素不是待排序序列的第一个元素,将其和第一个元素互换。
  3. 从余下的 N - 1 个元素中,找出关键字最小的元素,重复步骤 2,直到排序结束。

3.3 C语言实现n

int *selectSort (int *sums, int sumsSize, int *returnSize) {
	int start;
	int end;
	int min;
	int temp;
	for (int end = 0; end < sumsSize; end++) {
		min = end;
		for (int start = end + 1; start < sumsSize; start++) {
			if (sums[start] < sums[min]) {
				min = start;
				}
		}
	}
	temp = sums[min];
	sums[min] = sums[end];
	sums[end] = temp;	
	*returnSize = numsSize;
    return back;
    }
	 

4.冒泡排序

4.1 算法图

图片引用自知乎 链接: 冒泡排序算法原理及实现(超详细)
Alt
Alt

4.2 算法步骤

冒泡排序是一种简单的排序算法,其基本思想是比较相邻的两个元素,如果顺序不对就交换它们的位置,从而把最大(或最小)的元素逐渐“冒泡”到数组的最后。

  1. 从数组的第一个元素开始,依次比较相邻的两个元素,如果顺序不对就交换它们的位置,直到将整个数组中最大的元素交换到了最后一个位置。
  2. 重复执行步骤 1,但不包括已经排序好的最后一个元素,直到将整个数组排序完成。

4.3 C语言实现

int *bubbleSort (int *sums, int sumsSize, int *returnSize) {
	int temp;
	for (int i = 0; i < sumsSize; i++) {
		for (int j = i; j < sumsSize - 1; j++) {
			if (sums[j] < sums[j+1]) {
					temp = sums[j];
					sums[j] = sums[j+1];
					sums[j+1] = temp;
					}
			}
	}
	*returnSize = numsSize;
    return back;
}

5.快排

5.1 算法图

图片引用自blog 链接: 快速排序算法详解(原理、实现和时间复杂度)
Alt
Alt
Alt

5.2 算法步骤

  1. 选择枢轴元素:从待排序序列中选择一个元素作为枢轴元素,通常选择第一个元素、最后一个元素或者中间位置的元素作为枢轴元素。
  2. 划分序列:将待排序序列按照枢轴元素的大小关系分成左右两个子序列,小于枢轴元素的放在左边,大于枢轴元素的放在右边,相等的可以放在任一侧。
  3. 递归排序:对左右两个子序列分别进行递归排序,直到子序列的长度为1或0,此时子序列已经有序。
  4. 合并序列:将左子序列、枢轴元素、右子序列依次合并成一个有序序列,即为最终的有序序列。

从后往前再从前往后,从后往前找小的,因为要把小的放在数组前面。从前往后找大的,因为要把大的放在数组后边(这是从小到大排列)。

5.3 C语言实现

void quickSort (int *nums, int forward, int backward) {
    int start = forward;
    int end = backward;
    int key = forward;
    int tmp;
    //printf("%d ", forward);
    if (forward < backward) {
        while (start < end) {
            for (; end > start; end-- ) {
                if (nums[end] < nums[key]) {
                    tmp = nums[key];
                    nums[key] = nums[end];
                    nums[start] = tmp;
                    key = end;
                    break;
                }
            }
            for (; start < end; start++) {
                if (nums[start] > nums[key]) {
                    tmp = nums[key];
                    nums[key] = nums[start];
                    nums[start] = tmp;
                    key = start;
                    break;
                }
            }
        }
        
        quickSort(nums, key + 1, backward); 
        quickSort(nums, forward, key - 1);
}
}

6.归并排序

算法图

图片引用自zhihu 链接: 【算法】排序算法之归并排序
Alt

6.2 算法步骤

  1. 分解(Divide):将n个元素分成个含n/2个元素的子序列。
  2. 解决(Conquer):用合并排序法对两个子序列递归的排序。
  3. 合并(Combine):合并两个已排序的子序列已得到排序结果。

6.3 C语言实现

void mergeSort (int *nums, int *sorted, int forward, int backward) {
    //printf("(%d,%d)", forward, backward);
    if (forward < backward) {
        int mid = ((backward - forward) / 2) + forward;
        int firstStart = forward, firstEnd = mid;
        int secondStart = mid + 1, secondEnd = backward;
        mergeSort(nums, sorted, firstStart, firstEnd);
        mergeSort(nums, sorted, secondStart, secondEnd);
        int outCount = forward;
        while (firstStart <= firstEnd && secondStart <= secondEnd) {
            sorted[outCount++] = nums[firstStart] < nums[secondStart] ? nums[firstStart++] : nums[secondStart++];
        }
        while (firstStart <= firstEnd) {
            sorted[outCount] = nums[firstStart];
            ++outCount;
            ++firstStart;
        }
        while (secondStart <= secondEnd) {
            sorted[outCount] = nums[secondStart];
            ++outCount;
            ++secondStart;
        }
        for (outCount = forward; outCount <= backward; outCount++) {
            nums[outCount] = sorted[outCount];
        }
    }
}

7.桶排序

7.1 算法图

图片引用自zhihu 链接: 【算法】排序算法之桶排序
图片挂了 就先不放了

7.2 算法步骤

  1. 设置一个定量的数组当作空桶子。
  2. 寻访序列,并且把项目一个一个放到对应的桶子去。
  3. 对每个不是空的桶子进行排序。
  4. 从不是空的桶子里把项目再放回原来的序列中。

7.3 C语言实现

实现代码先分n份之后再进行排序,代码略。

8.希尔排序

8.1 算法图

图片引用自zhihu 链接: 希尔排序就这么简单
Alt

8.2 算法步骤

同上图

8.3 C语言实现

void mergeSort (int *nums, int n) {
    int gap = n / 2;
    int tmp;
    while (gap > 0) {
        for (int i = gap; i < n; i++) {
            tmp = nums[i];
            int j = i - gap;
            while (j >= 0 && tmp < nums[j]) {
                nums[j + gap] = nums[j];
                j -= gap;
            }
            nums[j + gap] = tmp;
            for (int i = 0; i < n; i++) {
        }
        }
        gap /= 2;
        
    }
}

9.计数排序

9.1 算法步骤

  1. 找出待排序数组中最大和最小的元素
  2. 统计数组中每个值为i的元素出现的次数,存入数组C的第i项
  3. 对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加)
  4. 反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1

9.2 C语言实现

void CountSort(int *a, int len)
{
    assert(a);
    //通过max和min计算出临时数组所需要开辟的空间大小
    int max = a[0], min = a[0];
    for (int i = 0; i < len; i++)
    {
        if (a[i] > max)
            max = a[i];
        if (a[i] < min)
            min = a[i];
    }
    //使用calloc将数组都初始化为0
    int range = max - min + 1;
    int *b = (int *)calloc(range, sizeof(int));
    //使用临时数组记录原始数组中每个数的个数
    for (int i = 0; i < len; i++)
    {
        b[a[i] - min]++;
    }
    //从后往前遍历原始数组,根据临时数组中记录的个数,将原始数组中的数据放到合适的位置上
    for (int i = len - 1; i >= 0; i--)
    {
        a[--b[a[i] - min]] = a[i];
    }
}

10.堆排序

10.1 算法图

Alt

10.2 算法步骤

  1. 首先将待排序序列构建成一个大顶堆(或小顶堆),此时序列的最大值(或最小值)为根节点
  2. 然后将根节点与最后一个元素交换,将最大值(或最小值)放到序列末尾
  3. 再将剩余的n-1个元素重新构建成一个大顶堆(或小顶堆),重复上述操作,直到只剩一个元素为止

10.3 C语言实现

void swap (int *a, int *b) {
    int tmp = *a;
    *a = *b;
    *b = tmp;
}

void heapFind(int *nums, int *output, int n) {
    for (int i = n / 2; i >= 0; i--) {
        heapSort(nums, n, i);
    }
    for (int i = n - 1; i > 0; i--) {
        swap(&nums[i], &nums[0]);
        heapSort(nums, i, 0);
        output[i] = nums[i];
    }
}

// 16 1 0 9 100
// 100 16 0 9 1

void heapSort(int *nums, int n, int i) {
    int tmp;
    int child;
    for (tmp = nums[i]; 2 * i + 1 < n; i = child) {
        child = 2 * i + 1;
        if (child != n - 1 && nums[child + 1] > nums[child]) 
            child++;
        if (tmp < nums[child]) {
            nums[i] = nums[child];
        } else {break;}
    }
    nums[i] = tmp;
}

11.基数排序

11.1 算法图

Alt

11.2 算法步骤

将所有待比较数值统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值