【数据结构】【排序】其实超级简单啦!

软件设计师知识点总结:数据结构与算法(超级详细) 本文系统梳理了数据结构与算法核心知识点,涵盖线性结构、树、图、排序与查找算法。主要内容包括:1.数据结构三要素(逻辑结构、存储结构、运算)和算法复杂度分析(时间/空间复杂度);2.线性结构(顺序表、链表、栈、队列)的实现与操作;3.树结构(二叉树、哈夫曼树)的性质与遍历;4.图的存储(邻接矩阵/表)与遍历(DFS/BFS);5.经典排序算法(插入、交换、选择、归并类)的原理与实现;6.查找算法(顺序、二分、哈希)的适用场景。重点解析了快速排序、堆排序等核心算法的实现细节与优化策略 阅读详情

本博客的所有代码都已测试完毕,请放心使用哟❤
在文章的最后面会贴出全部的码源,各位行行好点个赞吧(小狗哭泣)QAQ

一、排序的概念及其运用

1.1 排序的概念

排序:所谓排序,就是使一串记录,按照其中的某个的某个或者某些关键字的大小,递增或递减的排序起来的操作。
内部排序:数据元素全部放在内存中的排序。
外部排序:数据元素太多导致不能同时放在内存中,根据排序的要求不能在内外存之间移动的数据的排序。

这个就只是概念,话不多说我们直接开始吧!

1.2 常见的排序算法

在这里插入图片描述

看着蛮多的,但是没关系,让我们来逐一击破!


二、常见的排序算法

首先首先:在最开始的时候我们要理解一下函数!
非常重要!!

注意:本次排序都是以增序的基础写的

//交换
//在所有排序中,元素的交换是非常频繁的,所以在这里先包装,后续交换就可以直接引用
void Swap(int *p1, int*p2)
{
    int tmp = *p1;
    *p1 = *p2;
    *p2 = tmp;
}

//打印 -> 将数组里的数全部打印出来
void PrintArray(int* a, int n)
{
    for(int i = 0; i<n; i++)
    {
        printf("%d", a[i]);
    }
    printf("\n");
}


2.1插入排序

基本思想 :相比都玩过扑克牌吧,插入排序就跟扑克牌一样,运用到了排序思想,将一个个元素插入到 已排入的有序序列中。

1.直接插入排序

⭐以 下 为 动 图 展 示 ⬇:
请添加图片描述


⭐ 代 码 实 现 ⬇

//直接插入
void InsertSort(int* a, int n) {
   //我们假设一个end的位置
   //我们希望在[0,end]的范围中,从 end+1 下标的元素往前插入
   //end 往前遍历
   for (int i = 0; i < n - 1; i++){  //套一层循环控制 end 的起始位置
   	int end = i;
   	int tmp = a[end + 1];  //把后一个数据保存起来,因为在排序过程中前面的数会往后覆盖
   	while (end >= 0)
   	{  //如果tmp里面的值小于的话,那么就继续往前移动
   		if (tmp < a[end]){
   			a[end + 1] = a[end];
   			--end;
   		}else{//如果比他大就直接放在该下标的后一个位置
   			break;
   		}
   	}
   	//将插入的代码放到循环体外面是为了防止 tmp 要插入到数组首元素而导致end为-1
   	//这样循环就进不去了
   	a[end + 1] = tmp;
   }
}
直接插入排序的特性总结:
1.元素集合越接近有序,直接插入排序算法的时间效率越高
2.时间复杂度O(N^2)
3.空间复杂度O(1) 👉 他是一个稳定的排序算法 👈
4.稳定性: 稳定

2.希尔排序

希尔排序法又称缩小增量法。
希尔排序法的基本思想是:先选定一个整数,把待排序文件中所有记录分成个组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。
然后,取,重复上述分组和排序的工作。当到达=1时,所有记录在统一组内排好序。

其中:gap为间距
间距为gap的分为一组,对每一组执行插入排序

⭐以 下 为 动 图 展 示 ⬇:
请添加图片描述

我们可以很明显的看到,其实希尔排序的代码和直接插入排序大差不差的。 直接插入中的间距时1 ,所以是+1 然而希尔排序的间距是 gap ,所以是+ gap

//这一组完成的是一组的插入排序
void ShellSort(int* a, int n)
{
	int gap = 3;
	for (int i = 0; i < n-gap; i += gap)
	{
		int end = i;
		int tmp = a[end + gap];
		while (end >= 0)
		{
			if (tmp < a[end])
			{
				a[end + gap] = a[end];
				end -= gap;
			}
			else
			{
				break;
			}
		}
		a[end + gap] = tmp;
	}
	
}

可以对比一下两端代码的区别
在这里插入图片描述

但是这样排序只能接近有序,但并不是完全有序

⭐ 代 码 实 现 ⬇

//ShellSort函数实现
void ShellSort(int* a, int n)
{
    int gap = n; //初始间隔为数组长度
    while (gap > 1) //只要间隔大于1
    {
        gap = gap / 3 + 1; //将间隔缩小为原来的1/3

        for (int i = 0; i < n - gap; i++) //对每个间隔进行插入排序
        {
            int end = i; //初始化结束位置
            int tmp = a[end + gap]; //取出下一个位置的元素
            while (end >= 0) //从后往前遍历,找到插入位置
            {
                if (tmp < a[end]) //如果当前元素比当前位置元素小,则将当前位置元素向后移动
                {
                    a[end + gap] = a[end];
                    end -= gap;
                }
                else //如果当前位置元素比当前元素大或相等,则结束循环
                {
                    break;
                }
            }

            a[end + gap] = tmp; //将元素插入到当前位置
        }

        //PrintArray(a, n); //打印排序后的数组
    }
}
希尔排序的特性总结
1.希尔排序是对直接插入排序的优化。
2.当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就
会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。
3.希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些树中给出的
希尔排序的时间复杂度都不固定:

2.2 选择排序

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

1.选择排序

选择排序:
⭐在元素集合array[i]–array[n-1]中选择关键码最大(小)的数据元素
⭐若它不是这组元素中的最后一个(第一个)元素,则将它与这组元素中的最后一个(第一个)元素交换
⭐在剩余的array[i]–array[n-2](array[i+1]–array[n-1])集合中,重复上述步骤,直到集合剩余1个元素

⭐以 下 为 动 图 展 示 ⬇:
请添加图片描述
他的核心思想是遍历一遍时将最小的筛选出来,然而我们可以改良,不仅将最小的选出来,也可以将最大的选出来

⭐ 代 码 实 现 ⬇

//选择排序
void SelectSort(int* a, int n)
{   //注意的是,我们交换的是数组的下标而不是数组的元素哟
	int begin = 0, end = n - 1;  //给数组的两端分别定义begin和end,小的放左边,大的放右边
	while (begin < end) //循环结束的条件
	{   
		int mini = begin, maxi = begin; //定义一个最小值和一个最大值
		for (int i = begin; i <= end; i++)
		{
			if (a[i] < a[mini])
			{
				mini = 1;
			}
			if (a[i] > a[maxi])
			{
				maxi = i;
			}
		}
		Swap(&a[begin], &a[mini]);//最小值跟左边换,最大值跟右边换
		if (maxi == begin)  // 防止begin和maxi重叠后发生的双重交换
		{   //说明maxi被换到了mini
			maxi = mini;
		}
		Swap(&a[end], &a[maxi]);
		++begin;
		--end;  //每一次遍历之后都要缩小范围然后继续遍历
	}
}
选择排序的特性总结
1.直接选择排序思考非常好理解,但是效率不是很好。实际中很少使用
2.时间复杂度:O(N^2)
3.空间复杂度:O(1)
4.稳定性:不稳定

2. 堆排序

堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据。需要注意的是排升序要建大堆,排降序建小堆。
👉总的来说: 利用堆删除思想来进行排序

⭐以 下 为 动 图 展 示 ⬇:

请添加图片描述
⭐ 代 码 实 现 ⬇

//堆排序
void AdjustDown(int* a, int n, int parent)
{
    int child = parent * 2 + 1; //获取父节点的子节点
    while (child < n) //只要子节点存在
    {
        //假设法,选出左右孩子中小的那个孩子
        if (child + 1 < n && a[child + 1] < a[child])
        {
            ++child; //将较大的子节点忽略,选择较小的子节点
        }
        if (a[child] < a[parent]) //如果子节点比父节点小
        {
            Swap(&a[child], &a[parent]); //交换子节点和父节点
            parent = child; //更新父节点
            child = parent * 2 + 1; //重新获取父节点的子节点
        }
        else //如果子节点已经比父节点大或相等了,说明父节点已经是最大值了
        {
            break; //结束循环
        }
    }
}

void HeapSort(int* a, int n)
{
    // a数组直接建堆O(N)
    for (int i = (n - 1 - 1) / 2; i >= 0; --i) //从最后一个非叶子节点开始,逐个向下调整堆
    {
        AdjustDown(a, n, i); //调用调整函数
    }

    int end = n - 1; //排序的最后一个位置
    while (end > 0) //只要还有待排序的元素
    {
        Swap(&a[0], &a[end]); //将堆顶元素和最后一个元素交换
        AdjustDown(a, end, 0); //重新调整堆
        --end; //下一个待排序元素
    }
}

2.3 交换排序

1.冒泡排序

其核心是每一次遍历都会将最大的值排在后面,就像冒泡了一样。

⭐以 下 为 动 图 展 示 ⬇:

请添加图片描述

⭐ 代 码 实 现 ⬇

//冒泡排序
void BubbleSort(int* a, int n) 
{   //由于每一次遍历都排完了一个元素
	//所以在这里每一次的最后一个元素的下标都要-1
	for (int j = 0; j < n - 1; j++)
	{
		//注意:在这里给 i = 1 是为了后续与前一个元素进行比较,不会越界访问
		for (int i = 1; i < n - j; i++)
		{
			if (a[i - 1] > a[i])
			{  //交换
				Swap(&a[i - 1], &a[i]);
			}
		}
	}
}

👉在以上冒泡排序的代码实现过程中,我们仍然可以优化 👈 :
当我们在一次遍历过程中,没有发生数据交换,那么说明已经排序完毕,可以直接退出

在这里我们可以定义一个 exchange=1 如果发生交换则 exchange=0
当遍历一遍后 if 满足 exchange=1 则没有发生交换:

⭐ 优 化 后 代 码 实 现 ⬇

//冒泡排序
void BubbleSort(int* a, int n) 
{   for (int j = 0; j < n - 1; j++)
	{
		int exchange = 0;
		for (int i = 1; i < n - j; i++)
		{
			if (a[i - 1] > a[i])
			{  
				Swap(&a[i - 1], &a[i]);
				exchange = 1; //交换后为1
			}
		}
		if (exchange == 0)
			break;
	}
}
冒泡排序的特性总结:
1.冒泡排序是一种非常容易理解的排序
2.时间复杂度:O(N^2)
3.空间复杂度:O(1)
4.稳定性:稳定

2.快速排序(※重点)

基本思想:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。

⭐以 下 为 动 图 展 示 ⬇:
请添加图片描述
注意: 我们可以看到,下面在第一遍遍历的时 候,数值 6 刚好就排到了数组的第六个位置
👉因为在左右指针遍历的时候:p点为 6, 所有比p点小的都换到了左边,所以在最后 L == R 时,左边全是小于** 6** ,右边都是小于6 。于是6 就被换到了 正确的位置


看了动图是否感觉还有些茫然,不着急,下面有代码的大纲,尝试去理解一下

/ 假设按照升序对array数组中[left, right)区间中的元素进行排序
void QuickSort(int array[], int left, int right)
{
 if(right - left <= 1)
 return;
 
 // 按照基准值对array数组的 [left, right)区间中的元素进行划分
 int div = partion(array, left, right);
 
 // 划分成功后以div为边界形成了左右两部分 [left, div) 和 [div+1, right)
 // 递归排[left, div)
 QuickSort(array, left, div);
 
 // 递归排[div+1, right)
 QuickSort(array, div+1, right);
}

🔺快速排序也需要用到递归展开图哟
在这里插入图片描述

==当我们直接实现代码的话可能会忽略一些细节!
👇以下是一些重要的需要注意的:


1. 二者相遇会分两种情况
在这里插入图片描述
⭐ L 遇 R :R 先走, R 在比 key 小的位置停下来, L 没有找到比 key 大的,就会和 R 相遇,则 ➡️ 相遇位置就是 R 停下来的位置, 是比 key 小的位置
》
⭐ R 遇 L :第一轮以后的,先交换了, L 位置小于 key, 位置的值大于 key, R 启动找小,没有找到,与 L 相遇,则 ➡️ 相遇位置就是 R 停下来的位置, 是比 key 小的位置

第一轮R遇L,那么就是R没有找到小的,直接就一路左移,遇到L, 也就是 key 的位置

⭐ 代 码 实 现 ⬇

//快速排序
void QuickSort(int* a, int left, int right)
{    //我们一般会选择右边先走,所以代码实现统一以右边先走为例子
	if (left >= right)
		//如果区间不存在或者只有一个数了,那就不需要排序了,直接返回
		return; 
	int keyi = left;

	int begin = left, end = right;

	while (left < right)
	{
		//right 先走,找小的
		while (a[right] > a[keyi])
		{
			--right;
		}

		//left再走,找大
		while (a[left] > a[keyi])
		{
			++left;
		}
		//当左边找到比key大的,右边找到比key小的
		// 跳出循环时说明已经找到,交换即可
		Swap(&a[left], &a[right]); 
	}
	Swap(&a[left], &a[keyi]);
	keyi = left;
	// [begin, keyi-1] keyi [keyi+1, end]
	//由于我们需要使用递归来完成排序,所以左右的下标一定要记清楚
	QuickSort(a, begin, keyi - 1);
	QuickSort(a, keyi + 1, end);
}

❓ 但是这里会有一个弊端,就是当数组是有序的时候,是最坏的情况
因为每一次的都会是最左边那个值确定,那么就要递归数组长度次数,这就是最坏的情况O(N^2)

在这里插入图片描述

👇有两种优化的方法:

1.随机数选择 key

void QuickSort1(int* a, int left, int right) {
	if (left >= right)
		return;
	int keyi = left;
    int begin = left, end = right;

	//注意,优化后的快排是为了应对数组是有序时造成的最坏情况
	//--------begin----------
	int randi = rand();  //设置一个随机值做 key
	randi %= (right - left); //取模之后,随机值就会固定在这个区间里面
	randi += left;  
	//加上 left 是为了确保下标在正确的区间内(因为区间的下标不一定从零开始,也有可能从 key 的边开始)
	Swap(&a[left], &a[randi]);
	//---------end-----------

	while (left < right)
	{
		//right 先走,找小的
		while (a[right] > a[keyi])
		{
			--right;
		}

		//left再走,找大
		while (a[left] > a[keyi])
		{
			++left;
		}
		Swap(&a[left], &a[right]);
	}
	Swap(&a[left], &a[keyi]);
	keyi = left;
	
	QuickSort(a, begin, keyi - 1);
	QuickSort(a, keyi + 1, end);
}

2.三数取中
顾名思义,是指三个数选取大小中等的数为 key
left mid right

int GetMidi(int* a, int left, int right)
{
    int mid = (left + right)/2;
    if(a[left) < a[mid]
    {
        if(a[mid] < a[right])
        {
            return mid;
        }
        else if(a[left] > a[right])
        {
            return left;
        }
        else
        {
            return right;
        }
    }
    else  //a[left] > a[mid]
    {
        if(a[mid] > a[right]
        {
            return mid;
        }
        else if(a[left] > a[right])
        {
            return right;
        }
    }
}
//不过一般都不会用这种方法,所以我就放一个伪代码在这里

当然当然啦,如果你觉得这个快排很复杂,没关系!下面有前后指针版本的快排,代码实现也很简单❤

⭐以 下 为 动 图 展 示 ⬇:
请添加图片描述
具体实现方法:
1、 cur > key 👉 ++cur
2、 cur < key 👉 ++prev, 交换prev和cur的位置的值

在这里插入图片描述


    1. prev 紧跟 cur 一前一后
    1. prev 和 cur 之间是比 key 大的值

⭐ 代 码 实 现 ⬇

void QuickSort2(int* a, int left, int right) 
{//指针实现!
	int keyi = left;
	int prev = left;
	int cur = left + 1;

	while (cur < right)
	{
		if (a[cur] < a[keyi] && ++prev != cur)
			Swap(&a[prev], &a[cur]);
		
		cur++;
	}
	Swap(&a[keyi], &a[prev]);
	keyi = prev;

    // [left, keyi-1] keyi [keyi+1, right]
    //由于我们需要使用递归来完成排序,所以左右的下标一定要记清楚
    QuickSort(a, left, keyi - 1);
    QuickSort(a, keyi + 1, right);
}

快速排序的特性总结:

  1. 快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫快速排序
  2. 时间复杂度:O(N*logN)
  3. 空间复杂度:O(logN)
  4. 稳定性:不稳定

最后的知识点咯!

我们前面的快排都是递归实现的,那么该如何实现非递归呢?
我们需要用栈来实现!
//没有栈的小伙伴我可以…额发一份出来,制作不易还请不要辜负QAQ

取栈顶区间,单趟排序,右左子区间入栈

请添加图片描述
⭐ 代 码 实 现 ⬇

void QuickSortNonR(int* a, int left, int right)
{   //非递归
	Stack st;  //这里要引用栈的头文件
	
	StackInit(&st);
	StackPush(&st, left);
	StackPush(&st, right);
	while (StackEmpty(&st) != 0)
	{
		right = StackTop(&st);
		StackPop(&st);
		left = StackTop(&st);
		StackPop(&st);

		if (right - left <= 1)
			continue;
		int div = PartSort1(a, left, right);
		// 以基准值为分割点,形成左右两部分:[left, div) 和 [div+1, right)
		StackPush(&st, div + 1);
		StackPush(&st, right);

		StackPush(&st, left);
		StackPush(&st, div);
	}

	StackDestroy(&s);
}

最后最后,代码汇总咯!(撒花~❀)

真不容易啊,写到这里,凌晨的我发出了欣慰但又有一点虚弱的笑容:)

我们将各个的排序进行比较
在这里插入图片描述

sort.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>

void PrintArray(int* a, int n);

void InsertSort(int* a, int n);//直接插入
void ShellSort(int* a, int n);//希尔排序

void SelectSort(int* a, int n);//选择排序
void HeapSort(int* a, int n);//堆排序

void BubbleSort(int* a, int n);//冒泡排序
void QuickSort(int* a, int left, int right);//快速排序

sort.c

#include"sort.h"

//交换
void Swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}


//打印
void PrintArray(int* a, int n) {
	for (int i = 0; i < n; i++)
	{
		printf("%d ", a[i]);
	}
	printf("\n");
}



//直接插入
void InsertSort(int* a, int n) {
	//我们假设一个end的位置
	//我们希望在[0,end]的范围中,从 end+1 下标的元素往前插入
	//end 往前遍历
	for (int i = 0; i < n - 1; i++){  //套一层循环控制 end 的起始位置
		int end = i;
		int tmp = a[end + 1];  //把后一个数据保存起来,因为在排序过程中前面的数会往后覆盖
		while (end >= 0)
		{  //如果tmp里面的值小于的话,那么就继续往前移动
			if (tmp < a[end]){
				a[end + 1] = a[end];
				--end;
			}else{//如果比他大就直接放在该下标的后一个位置
				break;
			}
		}
		//将插入的代码放到循环体外面是为了防止 tmp 要插入到数组首元素而导致end为-1
		//这样循环就进不去了
		a[end + 1] = tmp;
	}
}

//希尔排序
void ShellSort(int* a, int n)
{
	int gap = n;
	while (gap > 1)
	{
		gap = gap / 3 + 1;

		for (int i = 0; i < n - gap; i++)
		{
			int end = i;
			int tmp = a[end + gap];
			while (end >= 0)
			{
				if (tmp < a[end])
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}

			a[end + gap] = tmp;
		}

		//PrintArray(a, n);
	}
}

//-----------------------------------

//选择排序
void SelectSort(int* a, int n)
{   //注意的是,我们交换的是数组的下标而不是数组的元素哟
	int begin = 0, end = n - 1;  //给数组的两端分别定义begin和end,小的放左边,大的放右边
	while (begin < end) //循环结束的条件
	{   
		int mini = begin, maxi = begin; //定义一个最小值和一个最大值
		for (int i = begin; i <= end; i++)
		{
			if (a[i] < a[mini])
			{
				mini = 1;
			}
			if (a[i] > a[maxi])
			{
				maxi = i;
			}
		}
		Swap(&a[begin], &a[mini]);//最小值跟左边换,最大值跟右边换
		if (maxi == begin)  // 防止begin和maxi重叠后发生的双重交换
		{   //说明maxi被换到了mini
			maxi = mini;
		}
		Swap(&a[end], &a[maxi]);
		++begin;
		--end;  //每一次遍历之后都要缩小范围然后继续遍历
	}
}
	

//堆排序
void AdjustDown(int* a, int n, int parent)
{
	int child = parent * 2 + 1;
	while (child < n)
	{
		//假设法,选出左右孩子中小的那个孩子
		if (child + 1 < n && a[child + 1] < a[child])
		{
			++child;
		}
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}
void HeapSort(int* a, int n)
{
	// a数组直接建堆O(N)
	for (int i = (n - 1 - 1) / 2; i >= 0; --i)
	{
		AdjustDown(a, n, i);
	}

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





//----------------------------------------

//冒泡排序
void BubbleSort(int* a, int n) 
{   //由于每一次遍历都排完了一个元素
	//所以在这里每一次的最后一个元素的下标都要-1
	for (int j = 0; j < n - 1; j++)
	{
		int exchange = 0;
		//注意:在这里给 i = 1 是为了后续与前一个元素进行比较,不会越界访问
		for (int i = 1; i < n - j; i++)
		{
			if (a[i - 1] > a[i])
			{  //交换
				Swap(&a[i - 1], &a[i]);
				exchange = 1;
			}
		}
		if (exchange == 0)
			break;
	}
}



//快速排序
void QuickSort(int* a, int left, int right)
{    //我们一般会选择右边先走,所以代码实现统一以右边先走为例子
	if (left >= right)
		//如果区间不存在或者只有一个数了,那就不需要排序了,直接返回
		return; 
	int keyi = left;

	int begin = left, end = right;

	while (left < right)
	{
		//right 先走,找小的
		while (a[right] > a[keyi])
		{
			--right;
		}

		//left再走,找大
		while (a[left] > a[keyi])
		{
			++left;
		}
		//当左边找到比key大的,右边找到比key小的
		// 跳出循环时说明已经找到,交换即可
		Swap(&a[left], &a[right]); 
	}
	Swap(&a[left], &a[keyi]);
	keyi = left;
	// [begin, keyi-1] keyi [keyi+1, end]
	//由于我们需要使用递归来完成排序,所以左右的下标一定要记清楚
	QuickSort(a, begin, keyi - 1);
	QuickSort(a, keyi + 1, end);
}

void QuickSort1(int* a, int left, int right) 
{
	if (left >= right)
		return;
	int keyi = left;
    int begin = left, end = right;

	//注意,优化后的快排是为了应对数组是有序时造成的最坏情况
	//--------begin----------
	int randi = rand();  //设置一个随机值做 key
	randi %= (right - left); //取模之后,随机值就会固定在这个区间里面
	randi += left;  
	//加上 left 是为了确保下标在正确的区间内(因为区间的下标不一定从零开始,也有可能从 key 的边开始)
	Swap(&a[left], &a[randi]);
	//---------end-----------

	while (left < right)
	{
		//right 先走,找小的
		while (a[right] > a[keyi])
		{
			--right;
		}

		//left再走,找大
		while (a[left] > a[keyi])
		{
			++left;
		}
		Swap(&a[left], &a[right]);
	}
	Swap(&a[left], &a[keyi]);
	keyi = left;
	
	QuickSort(a, begin, keyi - 1);
	QuickSort(a, keyi + 1, end);
}

void QuickSort2(int* a, int left, int right) 
{//指针实现!
	int keyi = left;
	int prev = left;
	int cur = left + 1;

	while (cur < right)
	{
		if (a[cur] < a[keyi] && ++prev != cur)
			Swap(&a[prev], &a[cur]);
		
		cur++;
	}
	Swap(&a[keyi], &a[prev]);
	keyi = prev;

	// [left, keyi-1] keyi [keyi+1, right]
	//由于我们需要使用递归来完成排序,所以左右的下标一定要记清楚
	QuickSort(a, left, keyi - 1);
	QuickSort(a, keyi + 1, right);
}	


#include"Stack.h"
void QuickSortNonR(int* a, int left, int right)
{   //非递归
	ST st;
	StackInit(&st);
	StackPush(&st, left);  //先把当先的区间录进去
	StackPush(&st, right);
	while (StackEmpty(&st) != 0)  //如果栈不为空就继续
	{
		right = StackTop(&st);  
		StackPop(&st);
		left = StackTop(&st);
		StackPop(&st);

		if (right - left <= 1)
			continue;
		int div = PartSort1(a, left, right);
		// 以基准值为分割点,形成左右两部分:[left, div) 和 [div+1, right)
		StackPush(&st, div + 1);
		StackPush(&st, right);

		StackPush(&st, left);
		StackPush(&st, div);
	}

	StackDestroy(&st);
}

后面就是栈所需要的代码源,用来实现非递归的快排的前情提要

//stack.h
#pragma once

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>

typedef int STDataType;
typedef struct Stack
{
	STDataType* a;
	int top;
	int capacity;
}ST;

void STInit(ST* ps);
void STDestroy(ST* ps);
void STPush(ST* ps, STDataType x);
void STPop(ST* ps);
STDataType STTop(ST* ps);
int STSize(ST* ps);
bool STEmpty(ST* ps);


//stack.c
#include"Stack.h"

void STInit(ST* ps)
{
	assert(ps);

	ps->a = NULL;
	ps->top = 0;
	ps->capacity = 0;
}

void STDestroy(ST* ps)
{
	assert(ps);

	free(ps->a);
	ps->a = NULL;
	ps->top = ps->capacity = 0;
}


void STPush(ST* ps, STDataType x)
{
	assert(ps);

	// ˣ 
	if (ps->top == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		STDataType* tmp = (STDataType*)realloc(ps->a, newcapacity * sizeof(STDataType));
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}

		ps->a = tmp;
		ps->capacity = newcapacity;
	}

	ps->a[ps->top] = x;
	ps->top++;
}

void STPop(ST* ps)
{
	assert(ps);
	assert(!STEmpty(ps));

	ps->top--;
}

STDataType STTop(ST* ps)
{
	assert(ps);
	assert(!STEmpty(ps));

	return ps->a[ps->top - 1];
}

int STSize(ST* ps)
{
	assert(ps);

	return ps->top;
}

bool STEmpty(ST* ps)
{
	assert(ps);

	return ps->top == 0;
}

创作不易,还请多多支持。
谢谢(鞠躬)
请添加图片描述

数据结构与算法总结整理(超级全的哦!) 数据结构与算法基础大O表示法内存工作原理递归NP完全问题数据结构数组链表混合结构栈队列散列表图集合二叉树算法二分查找选择排序快速排序广度优先狄克斯特拉算法近似算法K最近邻算法策略D&C分而治之贪婪算法动态规划 基础 大O表示法 内存工作原理 递归 NP完全问题 数据结构 数组 链表 混合结构 栈 队列 散列表 图 集合 二叉树 算法 二分查找 选择排序 快速排序 广度优先 狄克斯特拉算法 近似算法 K最近邻算法 策略 D&C分而治之 贪婪算法 动态规划 ... 阅读详情

相关推荐

超级详细解读基本排序算法(不看后悔,带排序演示动画)

排序与我们日常生活中息息相关,比如,我们要从电话簿中找到某个联系人首先会按照姓氏排序、买火车票会按照出发时间或者时长排序、买东西会按照销量或者好评度排序、查找文件会按照修改时间排序等等。在计算机程序设计中,排序和查找也是最基本的算法,很多其他的算法都是以排序算法为基础,在一般的数据处理或分析中,通常第一步就是进行排序,比如说二分查找,首先要对数据进行排序。在Donald Knuth 的计算机程

litong09282039的博客 1万+

数据结构——排序的超级详解(Java版)

史上最全的排序,Java版,博主花费了很长时间搞出来的,大家一起学习

HANhylyxy的博客 1119

5-4课:超级简单的排序方法:选择排序

终于,我们要正式开始讲解排序算法啦!今天先来讲一个最最简单的排序算法:选择排序。 扑克牌小游戏 排列 1-10 开始讲算法之前,我们还是先来看一个小游戏: 以一副扑克牌为道具,取出其中某一花色的 1-10,打乱顺序,扔在桌上,然后对它们进行人肉排序。我们该怎么做呢? 既然都知道是 1-10 了,那就先找 A,再找 2,然后 3,4,5,……,10 不就得了。 这样做当然可以做到把同一花色牌的 1...

YeJuliaLi的博客 440

【数据结构】排序(上)

简单到复杂的排序方法,一起来学习~

s_little_monster的博客 1万+

Python实现耐心排序算法——超级归并排序

这个算法的思路比较清晰,实现起来也相对简单,但是由于牌堆需要作为一个新的数据结构,因此在Python中的实现相对其他语言会略显繁琐一些。当一个元素要被放进已有牌堆的时候,首先需要从已有牌堆中找到第一个比该元素大的牌堆,如果不存在比该元素大的牌堆,则将该元素追加到最后一张牌堆后面。耐心排序又称为超级归并排序,是一种排序算法,用于对一个序列进行排序。在已经构建好的所有牌堆中,每个牌堆都是有序的,可以使用归并排序的思想对这些牌堆进行合并。下面,我们就来详细介绍一下Python实现的耐心排序算法——超级归并排序。

m0_47037246的博客 230

易语言超级列表框排序技术实现

本文还有配套的精品资源,点击获取 简介:易语言超级列表框排序技术是一种在易语言编程环境下,通过高级功能对列表框中的数据进行高效管理的方法。超级列表框通过提供多列排序、自定义列宽、复选框等功能,改善用户交互体验。本技术涵盖了消息处理、自定义排序函数、数据保存、文本处理以及与Windows API交互等关键概念,是提升易语言用户界面设计与交互能力的基础。 1. 易语言...

weixin_35748962的博客 1759

宇宙最简单排序:桶排序

c++的排序方法非常多,比如啥冒泡啊、选择啊、插入啊......,有时候编游戏也用到排序,但我是一个很勤(lan)快(duo)的人,想冒泡什么的忒麻烦了,复杂度又高。

apple_59169997的博客 1877

易语言实现超级列表框数据排序实战

本文还有配套的精品资源,点击获取 简介:易语言是一种中文编程语言,旨在降低编程难度,让非计算机专业人士也能进行程序开发。提供的压缩包包含源代码,用于对超级列表框中的数据进行排序。超级列表框是易语言中的常用控件,能够展示多列数据并支持多种操作。学习这个源码,不仅可以掌握列表框排序的基本方法,还能深入理解易语言的编程思想,提升编程技巧和程序设计能力。 1. 易语言简介 ...

weixin_42591413的博客 2360

选择排序,超级简单

选择排序 ###思路 进行n-1次循环,每次循环中,从第i+1个位置起找出i后面的最小值与第i个位置进行交换。 ###代码 #include<stdio.h> int main() { int i,j; int arr[20]={0}; int n=0; scanf("%d",&n); for(i=0;i<n;i++) { scanf("%d",&arr[i]); } int min = 0; for(i=0;i<n-1;i++) {

lanjiakang的博客 107

西门子S7-200 SMART控制步进电机(二)

目录 一、开环运动控制方法 二、运动轴概述 三、配置运动控制向导 一、开环运动控制方法 S7-200 SMART CPU提供三种开环运动控制的方法: 1、脉冲宽度调制(PWM):内置于CPU中,用于速度、位置或占空比的控制 2、脉冲串输出(PTO):内置于CPU中,用于指定长度脉冲或指定距离的控制 3、运动轴:内置于CPU总,用于速度和位置的控制。本文所讲的就是通过运动轴实现步进电机的运动控制。 SR20和ST20 CP...

qq_43134642的博客 2万+

Android Termux 安装Kali Linux 或 kali Nethunter史诗级详细教程

Termux 安装kali

风云小虾米的博客 6万+

超级简单并查集详解

一、概述 并查集,在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中。 其实说白了大部分还是用于寻找两个点是否联通,求最小生成树。 二、分析 1、背景阐明 首先我们需要先阐明一个简单的道理,假如从A城能到B城,从B城能到C城,那么自然A城和C城联通。并查集便是基于这个理论。...

Superb_day 1万+

Windows批处理脚本实战:用Ping命令打造简易网络监控工具(附完整代码)

本文介绍如何利用Windows批处理脚本和Ping命令,快速构建一个轻量级、自动化的网络监控工具。该方案无需额外安装软件,通过周期性探测目标IP连通性,并将结果(成功、失败及延迟)自动记录到带时间戳的日志文件中,适合中小团队或临时监控需求,实现低成本、高效率的网络状态监控。

5f4d3s2a1q的博客 494

数据结构--手撕八大排序(超级详细)!!

排序是一种重要的算法,需要我们掌握的方法有很多比如最常见的八种排序算法:插入排序,希尔排序,直接选择排序,堆排序冒泡排序,快速排序,归并排序。当然还有一些其他的排序方法如基数排序,桶排序这里就不多做阐述。1. 冒泡排序和选择排序均为简单直观的排序算法,但是在大规模数据下效率较低。2. 插入排序在部分有序序列下具有较高的效率,但在一般情况下效率低于其他算法。3. 希尔排序通过分组插入排序的方式提高了效率,但在最坏情况下仍然是较慢的排序算法。

hyldzbg的博客 1335

从CD4051到现代模拟开关:40年芯片演进史与选型避坑指南

本文回顾了从CD4051到现代模拟开关的40年技术演进,详细对比了导通电阻、带宽等关键参数的显著提升。通过实际案例和选型矩阵,揭示现代模拟开关在精度、功耗和集成度方面的优势,并提供高精度测量、电池供电等场景的选型策略与避坑指南,帮助工程师优化设计。

weixin_42543046的博客 153

AMD Ross FPGA Agent 实战:用 AI 驱动 Vivado 开发流程

在 EDA 领域,FPGA 开发长期面临工具链重、反馈周期长、报错晦涩等痛点。AI Agent 通过自然语言交互与工具调用,将 Vivado 的 Tcl 批处理流程封装为可编排、可观测的智能体,显著降低查文档与读报告的时间成本。其核心在于 Harness 与 Agent 的协同:Harness 提供安全执行环境,Agent 负责决策与迭代。典型应用包括工程创建、约束生成、综合实现报告解读及比特流失败排查。本文以 AMD Ross 为例,拆解其架构设计与实操方法,帮助开发者理解如何将 Agent 落地到高门槛

weixin_29189363的博客 1034

数据结构知识点总结(超级详细)

逻辑结构描述的数据之间的关系;物理结构描述的是数据的内存中真实的存储状态。存储逻辑关系为 “一对一” 的数据,存取数据必须遵循 “先进后出” 的原则。存储逻辑关系为“一对一”的数据,存取数据必须遵循 “先进先出” 的原则。如果数据中存储大量无效的元素,可以采用压缩存储的方式。算法研究的是解决问题的方法。只对查找表做查找和读取元素的操作,不改变查找表的存储结构。二叉树的先序遍历算法(递归和非递归)二叉树的中序遍历算法(递归和非递归)二叉树的后序遍历算法(递归和非递归)图的十字链表存储结构(C语言实现)

数据结构和算法教程(C语言版) 3400

GPS系统跟踪捕获算法的Verilog实现在FPGA

本文将介绍GPS系统中的跟踪捕获算法,并提供该算法的Verilog实现在FPGA上运行的源代码。常用的方法是将接收到的信号与一个本地振荡器产生的参考信号进行混频,然后使用带通滤波器提取出希望得到的频率分量。码跟踪的目的是通过检测接收到的信号中的码片序列来实现对导航数据的解调。以上是一个简化的GPS系统跟踪捕获算法的Verilog实现,其中包含了时间检测、频率跟踪和码跟踪三个模块。GPS信号由载波频率和导航数据组成。跟踪捕获算法的目标是通过对接收到的信号进行处理,从而获取到准确的载波频率和导航数据。

PixelEnigma的博客 1108

快速排序(超级超级简单版本,一看就会)

<script> function quickSort(arr){ var left=[],right=[]; if(arr.length<1){ return arr; } var index = Math.floor(arr.length/2); var point...

素描本里的男子的博客 690

使用Matlab与V-REP联合仿真

在Matlab中,我们可以使用V-REP提供的远程API(Application Programming Interface)来连接到V-REP仿真环境。为了连接Matlab与V-REP,我们需要在Matlab中添加V-REP的远程API函数库。你可以根据具体的需求编写Matlab脚本来控制V-REP场景中的机器人,并进行系统建模和仿真。一旦成功连接到V-REP,我们可以使用Matlab来控制V-REP场景中的机器人。在本文中,我们将介绍如何使用Matlab与V-REP进行联合仿真,并提供相应的源代码。

HackMasterX的博客 1854

SAP_MM模块-服务类采购详细讲解案例

SAP_MM模块服务类采购订单配置及业务测试案例详解,包括前台业务操作、后台配置以及使用过程中的问题处理

风沙的博客 5125

探索数据结构世界之排序篇章(超级详细,你想看的都有)

本文将带你进入排序算法的世界,介绍一些常用的排序算法以及它们的优缺点

qq_67838572的博客 1393

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

【数据结构】—超级详细的归并排序(含C语言实现)

本文是作者对于归并排序的总结,归并排序非递归实现其实还有将后面的拷贝放到gap*=2旁边的,但是作者没有理解,后续会补上的(●''●)

B1ue还在专注 3076

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

排序算法之简单选择排序

简单选择排序算法思路:这个真的是超级简单的算法,从数组起点开始,每次循环都确定数组的一个空间存什么,里面的嵌套循环每次都要遍历未排序的部分来找到最小的数字,退出这个小循环后,将这个最小值放到当前操作的数组下标中。package choice; /*简单排序算法 * 思路:从每个点开始算起,将每个点与后面的点比较选出最小的点,存入当前点坐标,一直到循环完整个数组 * 复杂度O【n的平方】 * */ ...

Sunmeok的博客 240

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Java数据结构第一讲-排序算法

常见数据结构和算法实现(排序/查找/数组/链表/栈/队列/树/递归/海量数据处理/图/位图/Java版数据结构) 数据结构和算法作为程序员的基本功,一定得稳扎稳打的学习,我们常见的框架底层就是各类数据结构,例如跳表之于redis、B+树之于mysql、倒排索引之于ES,熟悉了底层数据结构,对框架有了更深层次的理解,在后续程序设计过程中就更能得心应手。掌握常见数据结构和算法的重要性显而易见,本文主要讲解了几种常见的数据结构及基础的排序和查找算法,最后对高频算法笔试面试题做了总结。本文会持续补充,希望对大家日

Jet_qi的博客 1614
上一篇: 【看完就会】零基础学习文件操作
下一篇: 【C++】【类与对象知识整理】(一)
Reuuse
博客等级 码龄3年 611粉丝 72原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Reuuse

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值