1.插入排序

2.希尔排序

3.选择排序

4.堆排序

5.冒泡排序

6.快速排序

7.归并排序

8.计数排序

---------------

插入排序

这个排序原来很简单,如图演示:

我们先把 9 看作有序数组插入,它比8大,那就交换位置

此时,8前面没有数字了,所以它就停下,再把8 9 看作有序数组:

再把 7 插入,因为9比7大,交换,8比7大,交换,就是这样:

重复这样的步骤,直到数组结/或者已经交换完全

实现代码如下:

// 插入排序
void InsertSort(int* a, int n)
{//因为tmp是当前下标的后一个元素比较,所以最后一个元素的位置是n-1for (int i = 0; i < n-1; i++){int n = i;int tmp = a[1 + n];//假设每次都要比到最后while (n >= 0){//如果小于,就让这个位置元素被替代,然后再跟前一个比较if (tmp < a[n]){a[n + 1] = a[n];n -= 1;}//如果不小,那就退出else{break;}}//它停下的位置就是前面已经没有比它小的元素了,但是因为上面替换之前-1,所以这里要+1a[n + 1] = tmp;}
}

-----------

时间复杂度:最好O(N^2),最坏O(N^2),因为它总要比较判断

空间复杂度:O(1),没有额外开辟空间

时间太慢了,不是很推荐

---------------

希尔排序

插入排序属实太慢了,假设一个很小的元素在最后面,那它要移动N次才能来到前面的位置(1在最后面,它要来到9的位置就要换8次)

所以它的改进版本,希尔排序就出来了,希尔排序是这么想的,有一个间隔数gap,这个数可以很大,也可以很小,它先将数组分为几个小组:

红色一组为:9 6 3

蓝色一组为:8 5 2

绿色一组为:7 4 1

我这里设置的gap是3,应该可以看的出来,然后分别对这几个小组排序:

9 6 3 变成 3 6 9

8 5 2 变成 2 5 8

7 4 1 变成 1 4 7

就变成这样,这里只是举例子,因为降序方便看就设置为这样,实际要混乱一点,然后再对这降序的再排一次(这里已经有序了就没画)

每一次排序都会让数组更加有序

如果这个gap很大,那小的数组会更快的来到前面,因为它一次可以跳gap格,大的也会更快的去到后面

如过这个gap很小,那它每次移动都会给更加有序,如果是1,那就跟插入排序一样了

这个gap肯定不能太小,并且不能是固定的数字,如果是固定的数字,那它每次移动就会很慢,所以最好跟N扯上关系,如果看懂了插入排序,那希尔就很好理解,它不过是把 n+1 变成了 n+gap,然后再插入

// 希尔排序
void ShellSort(int* a, int n)
{//定义一个gapint gap = n;while (gap > 1){//这个值就是间隔gap = gap / 3 + 1;//每次都是跟 n+gap比较,所以最后一个比较元素的位置是n-gapfor (int i = 0; i < n - gap; i++){//从这个下标开始,如果直接拿i的话会死循环int n = i;int tmp = a[n + gap];//如果这个n>0,那它前面还有没比较的值while (n >= 0){//比较if (tmp < a[n]){//交换,并且让n-gap,找到下一个间隔为gap的比较a[n + gap] = a[n];n -= gap;}else{break;}}//同理,最后一次这个n肯定被-gap,所以加上a[n+gap] = tmp;}}
}

时间复杂度: O (n *logn)

空间复杂度:O(1)

这个算法非常快,建议使用

-----------------

选择排序

最好理解的排序,每次找最大的(或者最小的),也可以一起找出来,然后跟第一个元素和最后一个元素换位置,换完就排完了

然后交换,找出次大的,次小的:

循环即可 ,但是一定要注意,因为这里一次交换两个值,所以可能出现:

原本最大值的下标是0,然后最小值的下标是3,最小值先跟0的位置换,这个最大值就被交换到3的位置去了,再去交换下标0就会找到最小值,所以先判断交换位置有没有冲突,有就调整

// 选择排序
void SelectSort(int* a, int n)
{//要交换的左右下标int left = 0, right = n - 1;while (left < right){//找出数组里面最大值和最小值的下标int max, min;max = min = left;for (int i = left+1; i <= right; i++){if (a[i] > a[max]){max = i;}if (a[i] < a[min]){min = i;}}//交换swap(&a[left], &a[min]);//如果最大值的下标是上面的left,那它就会被交换到min的位置,所以让max指向被交换后的位置if (max == left){max = min;}//再次交换swap(&a[right], &a[max]);//再换下一组left++;right--;}
}

时间复杂度:最好O(N^2),最坏O(N^2),因为不管怎么样它都要查找然后交换

空间复杂度:O(1),没有额外开辟空间

不是很快,不推荐使用

-----------

堆排序

这个在我以前专栏里面有详细说过,如果不了解堆的性质可以去看看,这里简单描述一下:

一个堆的堆顶是数组里面的最大值,那它就是大堆

一个堆的堆顶是数组里面的最小值,那它就是小堆

假设我们是升序,那我们就要建立大堆(降序建小堆),然后把堆顶的元素(也就是下标为0的元素)跟最后一个元素换,然后再调整一下堆即可

这里我就直接上代码实现了:

先是建立大堆的调整函数:

void AdjustDown(int* arr, int* root, int* end)
{//父亲节点int parent = root;//孩子节点int child = parent * 2+1;while (child < end){//选两个孩子里面大的那个if (arr[child + 1] > arr[child] && (child+1) <end){child++;}//如果父亲比孩子小,交换if (arr[parent] < arr[child]){swap(&arr[parent], &arr[child]);parent = child;child = parent * 2 + 1;}//不小就跳出else{break;}}
}

然后是排序:

// 堆排序
void HeapSort(int* a, int n)
{//先建立一个大堆for (int i = (n - 2)/2; i >= 0; --i){AdjustDown(a, i, n);}//最后一个元素的下标,交换使用int end = n - 1;while (end){//将最大的放到最后swap(&a[end], &a[0]);//重新调整堆AdjustDown(a, 0, end);//最后位置就不用排了end--;}
}

时间复杂度: O (n *logn)

空间复杂度:O(1)

这个算法跟希尔排序一个级别,除了代码比较多以外,还是很推荐的

-------------

冒泡排序

老朋友了,我相信这个我不说大家也明白,具体思路是:

如果前面一个大于后面一个,交换,然后遍历数组

// 冒泡排序
void BubbleSort(int* a, int n)
{for (int i = 0; i < n; i++){for (int j = 0; j < n; j++){if (a[j - 1] > a[j]){swap(&a[j - 1], &a[j]);}}}
}

就不写注释了,实在太简单了

时间复杂度:O(N^2)

空间复杂度:O(N)

不推荐使用,太慢了,太慢了,太慢了!!!

如果代码没问题但时间超时,多半是它的锅,别用

-------------

快速排序

这个不是那个qsort,但也挺快的

有好几种思路,先说第一种:

1、hoare版:

使用递归,看图演示:

假设这是要排序的数组,第一步,我们选一个数字作为Key,这里我选 6(第一个元素的位置) ,那我们就从6开始走,先走Key的另一边,如果我选左边,那就先走右边,选右边就先走左边:

右边要找到比Key小的值,因为Key是6,这里2比6小,所以停下

然后找左边:

左边找比Key大的值,5 4 都不符合条件,所以跳过,9比6大,所以停下,然后我们交换位置:

然后右边再继续先走,找到比6小的:,左边找比6大的

右边停在1,左边停在8,停下再次交换:

此时右边再开始走:

它们相遇了,这个时候我们就把这个位置的值跟Key(第一个元素的位置交换):

到这里,第一次就走完了,我们发现比Key小的都在左边,比Key大的都在右边,而6也来到了正确的位置,它的左边都比它小,它的右边都比它大

然后我们将数组分割:

在这两个数组里面重复上面的步骤,直到它们不可再分割为止:

第一次分割将数组分为两半,第二次将左边长的一段又变成两段...

看看代码理解:

// 单趟快排
int PartSort(int* a, int left, int right)
{//先将left现在的值保留下来(一般是0)int keyi = left;//如果左边大于右边那肯定相遇了while (left < right){// 找小while (left < right && a[right] >= a[keyi])--right;// 找大while (left < right && a[left] <= a[keyi])++left;//交换swap(&a[left], &a[right]);}//出来了就是相遇,这里的元素跟Key交换swap(&a[keyi], &a[left]);//返回中间的节点,将其分割为两段return left;
}

这是一趟,我们递归调用:

void QuickSort(int* a, int begin, int end)
{// 如果起始位址等于(或者大于)终点为止,那就可以返回了if (begin >= end)return;//这个值就是中点int keyi = PartSort(a, begin, end);//左半边,因为Key已经到了正确的为止,所以不用排了,left通常是0QuickSort(a, begin, keyi - 1);//右边,Key不排,结束为止就是end(数组长度)QuickSort(a, keyi + 1, end);return;
}

2、挖坑法

这种思路是这么的:

假设现在有这么一组数据,将最左边这个 6 保存下来,并让一个值指向这里,我们称之为pit(坑位)。

程序开始走,因为坑位在左边,所以要从右边开始走,right 从 7 开始,它的目标是找到比 6 小的数字:

7 < 6 ?

8 < 6 ?

9 < 6 ?

1 < 6 ?

它就停下来了 ,此时它指向 1 ,1 < 6

找到了小,我们就让 1 放到坑位里面,坑位就是这里的 6 :

此时,因为坑位到了右边,下一次就要从左边开始走,left 从 5 开始,找比 6 大的:

5 < 6 ?

4 < 6 ?

3 < 6 ?

2 <6 ?

1 < 6 ?

此时 left 来到 right 的位置,它们重叠了,而这里正好是 1 的位置,将一开始保存的 6 放到这里:

一趟排序就完成了,左边都是比 tmp(6) 小的,右边都是比它大的,随后我们递归调用即可:

// 快速排序挖坑法
int PartSort2(int* a, int left, int right)
{//坑位int pit = left;//keyint key = a[left];//一趟走N次while (left < right){//找小while (a[right] > key && left < right){right--;}//将找到的小放到坑里面,然后将这里变成新的坑a[pit] = a[right];pit = right;//找大while (a[left] < key && left < right){left++;}//将找到的大放到坑里面,然后将这里变成新的坑a[pit] = a[left];pit = left;}//它们相遇的位置,就是key的位置a[left] = key;
}

-------------

3、前后指针法

第一个指针指向 6

第二个指针指向 5

key 是第一个元素 6

如果 cur 位置的元素大于 key 并且  ++prev 的位置不等于 cur ,那就交换:

5 < 6 ? cur++;

4 < 5 ?   ++prev == cur ?

交换它们的值:

cur++;

3 < 6 ? ++prev == cur?

再次交换:

cur++;

.....

直到:

此时,cur处元素大于key,所以不执行交换,但是cur++

cur 大于 key

cur++

cur 大于 key

cur++

此时cur越界,所以循环停下,将prev的值跟key的值交换:

第一趟结束

// 快速排序前后指针法
int PartSort3(int* a, int left, int right)
{//前、后指针int prev = left;int cur = prev + 1;//key的值int key = left;while (cur <= right){//开始走if (a[cur] < a[key] && a[++prev] != a[cur]){swap(&a[prev], &a[cur]);}//每次cur都++cur++;}//交换swap(&a[prev], &a[key]);return prev;
}

----------

如何优化快排

小区间优化:

但看快排的代码,它是靠递归完成的,这样的一个好处是可以把一个很麻烦的问题分成小问题解决

但是缺点同样很明显,假设这一次只要排 4 个数据,你还分成好几个小块,就有点太麻烦了,所以我们可以在快排里面调用一下 插入排序,当要排序的小于一定个数时,就不递归了,直接排序

void QuickSort(int* a, int begin, int end)
{// 如果起始位址等于(或者大于)终点为止,那就可以返回了if (begin >= end)return;//小于13个就插入,这个区间可以自己定if (end - begin + 1 < 13){InsertSort(a, end - begin + 1);return;}//这个值就是中点int keyi = PartSort3(a, begin, end);//左半边,因为Key已经到了正确的为止,所以不用排了,left通常是0QuickSort(a, begin, keyi - 1);//右边,Key不排,结束为止就是end(数组长度)QuickSort(a, keyi + 1, end);return;
}

选择优化

另外,还有一个可以优化的地方,如果每次快排的 key 都是数组中间的数,那它的时间复杂度是

N*logN,那它的最坏情况呢?

如果每次都选到两边的数据,那它的时间复杂度毫无疑问的是 N^2,针对这种情况,我们还可以优化一个函数,确保key不是数组两边的数

int FindKey(int* a, int left,int right)
{int key = left + (left + right) / 2;if (a[left] < a[key]){if (a[right] > a[key]){return key;}else if (a[left] > a[right]){return left;}else{return right;}}else{if (a[key] > a[right]){return key;}else if (a[left] < a[right]){return left;}else{return right;}}
}

看着复杂,不过不算难,再将用到Key的地方全部换成这个函数优化key的选择,快排还能还进一步...

非递归实现

如何实现非递归?

那我们就要好好想想递归是来做什么的:

这是要排序的数组,快排递归实现就是如下图所示:

它会将选定的key排到它应该有的位置,而 左边都比它小,右边都比它大,随后,它将key左边传入函数,再递归,再将右边传入函数递归:

每一次,它都至少可以保证一个数字来到应该有的位置上,如此反复

...

如果要非递归,那我们就要实现的是每一次都传入一个区间,直到每个区间都覆盖到,这里就要用到之前的 队列/栈

我这里用的是栈, 在用之前,要先把栈的函数拷贝一份:


void StackInit(Stack* ps)
{assert(ps);ps->arr = NULL;ps->capacity = 0;ps->top = 0;
}void StackPush(Stack* ps, STDataType data)
{assert(ps);if (ps->top == ps->capacity){int newcapacity = ps->capacity == 0 ? 4 : (ps->capacity) * 2;ps->arr = (STDataType*)realloc(ps->arr, sizeof(Stack)* newcapacity);if (ps->arr == NULL){printf("realloc fail\n");exit(-1);}ps->capacity = newcapacity;}ps->arr[ps->top++] = data;
}void StackPop(Stack* ps)
{assert(ps);assert(ps->top > 0);ps->top--;
}STDataType StackTop(Stack* ps)
{assert(ps);return ps->arr[ps->top-1];
}int StackSize(Stack* ps)
{assert(ps);return ps->top;
}int StackEmpty(Stack* ps)
{assert(ps);return ps->top == 0;
}void StackDestroy(Stack* ps)
{assert(ps);free(ps->arr);ps->arr = NULL;ps->top = 0;ps->capacity = 0;
}

都是之前写过也用过好几次的代码了,这里就不重复说明了

思路是这样的:

已有一个数组,将它最左边的和最右边的下标压下去

这里压的是 6 和 8

循环判断,如果栈不为空,就进去

随后拿两个值来接收栈里面的值,一个是左下标,一个是右下标,对这一块空间排序

然后对它进行一次排序,随后它应该会被分成两块:

可以看到key左边是一块待排序的空间,右边也是一块待排序的空间

将它的左边压栈,它左边的空间是 0 - key-1

将它的右边压栈,它右边的空间是 key+1 - end(数组末尾)

不过在压栈之前,最好先判断一下它们中间有没有数据

如果此时数组还没排完,那栈里面应该还压着其他区间,随后再次读取数据

直到栈为空

void QuickSortNonR(int* a, int left, int right)
{//创建栈并初始化Stack st;StackInit(&st);//插入头尾StackPush(&st, left);StackPush(&st, right);//循环代替递归while (!StackEmpty(&st)){//因为后压的右下标,所以右下标先出来int right1 = StackTop(&st);StackPop(&st);int left1 = StackTop(&st);StackPop(&st);//对这一块空间排序int mid = PartSort2(a, left1, right1);//如果左边还有就压左边if (mid-1-left1>0){StackPush(&st, left1);StackPush(&st, mid - 1);}//右边还有就压右边if (right1-mid-1>0){StackPush(&st, mid + 1);StackPush(&st, right1);}}//排序完销毁栈StackDestroy(&st);
}

这里用的单趟快排上面可以复制,这里将不写了.

时间复杂度:O(N*logN)

空间复杂度:O(1)

挺快的,但代码很长...

------------

归并

如果做过这样的一道题,那归并的思路就很好理解了:

请合并两个有序数组,并让返回的数组依旧有序

先比较第一个数据

1 >  2  ?

新创建的数组的第一个元素就放小的那个,然后让 3 跟  2  比

2 小于 3

所以新数组第二个元素就放 2

然后 4 跟  3  比

.......

直到其中一个没有或者两个都比完:

这就叫归并

那归并排序是什么样的呢?

看图:

这是已有的数组

对其中每一块区域分别归并:

以左半边举例

9  3  8  6 显然无序

将它分为9  3   一组 8   6

9  3 也无序,所以将其分为   9  一组,3一组

然后归并就变成了

3  9

8  6归并就成了6  8

再将3  9 和6  8归并

3  6  8  9

递归的条件,即有多个元素,每次都分一半,直到没得分,这个时候就可以归并了

切记,归并不能在原数组归并,不然会丢失数据,所以要新建立一个临时数组,然后将这个数组的值拷贝进去

void _MergeSort(int*a, int begin, int end, int* tmp)
{//如果begin >= end  说明这个区间是无效区间,直接返回if (begin >= end)return;//每次都取一半int mid = (begin + end) / 2;//左半边_MergeSort(a, 0, mid, tmp);//右半边_MergeSort(a, mid+1, end, tmp);//单趟(归并没什么好说的吧?)int begin1 = begin ,  end1 = mid;int begin2 = mid + 1, end2 = end;int pos = begin;while (begin1 <= end1 && begin2 <= end2){if (a[begin1] < a[begin2])tmp[pos++] = a[begin1++];elsetmp[pos++] = a[begin2++];}//也许是其中一个数组放完了,另一个还没有,所以判断一下while (begin1 <= end1)tmp[pos++] = a[begin1++];while (begin2 <= end2)tmp[pos++] = a[begin2++];//别忘了拷贝过去memcpy(a + begin, tmp + begin, (end - begin + 1)*sizeof(int));
}// 归并排序递归实现
void MergeSort(int* a, int n)
{//新建立的临时数组,用于存放归并数组的数据int* tmp = (int*)malloc(sizeof(int)* n);assert(tmp);//调用归并函数_MergeSort(a, 0, n, tmp);free(tmp);
}

时间复杂度:O(N*logN)

空间复杂度:O(N)

不好用,别用

--------

非递归实现归并

非递归,就是模拟递归的一个过程

在递归实现里面,先将其中元素一个一个归并,然后再两个两个归并,再四个四个归并...

那是不是可以拿一个循环解决?

所以,非递归版本就这么来了:

首先要定义一个gap,这个gap是每次递归的区间

如果是1,每次就归并一个

如果是2,每次就归并两个

如果是4,每次就归并四个

...

每次都归并一个数组的长度,可以嵌套一个for循环

在定义两个数组的头尾指针

如果gap是1,预期的效果是每次比较1个,那头尾指针就该这么定义:

begin1 = 0,end1 = begin1+gap-1;

begin1是从0开始的,如果循环比较,那这里应该赋值为i(循环)

end1 则是 begin1 加个gap(间隔),但是别忘了-1才是下标

begin2 则是 begin+gap,这样就跳过了begin1的数组

end2 则是 begin2+gap-1,同end1原理

...

在走过一遍之后,要将gap*2,这样就可以一次归并两个长度为2的数组

...

切记

可能越界,因为gap每次乘2,及有发生以下情况:

end1越界了,那直接修改end1 = n(长度)-1

begin2 越界,那此时就要修改begin2和end2,因为判断条件是begin2 <= end2,所以只需要让begin2>end2即可

end2越界,此时需要将end2修改为 n(长度)-1

void MergeSortNonR(int* a, int n)
{//间隔 gapint gap = 1;int* tmp = (int*)malloc(sizeof(int)*n);//如果间隔大于长度,就不用比了while (gap < n){//每次都遍历一遍数组for (int i = 0; i < n; i += 2 * gap){int begin1 = i, end1 = i + gap - 1;int begin2 = i + gap, end2 =i+2*gap - 1;//判断可能越界的值if (end1 >= n)end1 = n - 1;// begin2 越界,第二个区间不存在if (begin2 >= n){begin2 = n;end2 = n - 1;}// begin2 ok, end2越界,修正end2即可if (begin2 < n && end2 >= n)end2 = n - 1;//这里完全是为了好看,如果报错这里可以看到每次的区间printf("%d %d %d %d\n", begin1, end1, begin2, end2);//归并int pos = begin1;while (begin1 <= end1 && begin2 <= end2){if (a[begin1] < a[begin2])tmp[pos++] = a[begin1++];elsetmp[pos++] = a[begin2++];}//也许是其中一个数组放完了,另一个还没有,所以判断一下while (begin1 <= end1)tmp[pos++] = a[begin1++];while (begin2 <= end2)tmp[pos++] = a[begin2++];//别忘了拷贝过去memcpy(a, tmp, sizeof(int)*end2);}gap = gap * 2;}//用完了释放,别忘记了free(tmp);
}

时间复杂度:O(N*logN)

空间复杂度:O(N)

不好用,别用

-------------

计数排序

一个比较简单的排序,如果理解的话,应该是这样理解的

这是要排序的数组,先建立一个数组,这个数组的大小应该是要排序里面数字的最大值

举个例子,这里最大的是9,所以就要开辟 10 个整型的空间(因为只有10个空间最后的下标才是9)

将待排序的数组元素作为下标,放到开辟空间对应的下标处,每放一个,就+1(初始化0)

打印的时候再将开辟数组里面不为0的地方打印出来

比方说这里有 2个3,那新开辟数组下标为3的位置就有 2 个,到时候返回就多返回一个

------

但是这样做有一个坏处,就是,如果用最大数字来开辟空间的话,那假设是这样的一个数组

10000 5000  9999   8888

最大值10000,也就是说要开辟10000个整型的空间,但前面4999个都用不到

于是就有了优化版本

以最小的为参考值

这里是5000

开辟空间时开辟 最大值-最小值+1的空间

放数据的时候再-一个最小值

再之后打印的时候再+最小值

比方说5000,它放进去的时候-5000,就会放到 0 的位置

打印的时候 0+ 5000,所以打印出来的就是5000

// 计数排序
void CountSort(int* a, int n)
{//找最大最小值int max, min;max = min = a[0];int i;for (i = 1; i < n; i++){if (a[i] > max){max = a[i];}if (a[i] < min){min = a[i];}}//开辟空间int range = max - min + 1;int* arr = (int*)calloc(range, sizeof(int));assert(arr);//开始计数for (i = 0; i < n; i++){arr[a[i]-min] +=1;}//放回原数组int j = 0;for (i = 0; i < range; i++){while (arr[i]--){a[j++] = i+min;}}//释放空间free(arr);arr = NULL;
}

时间复杂度:O(N+Range(数据范围))

空间复杂度:O(N+Range(数据范围))

适用于范围比较集中、数据量大的情况,如果类似 10000 1

还是不要用这种了

-------------

稳定性:

排序除了时间复杂度和空间复杂度以外,还有一个值得比较的是它的稳定性

稳定性可以用下图理解:

原本红色的99在黑的前面,现在排完序它们之间的相对位置还是没变,红的还是在黑的前面

上面的八个排序中:

1.插入排序:稳

每次移动一个,原本在前面的在移动后面的时候也不会变位

2.希尔排序:不稳

如果有两个同样的数据但被分到不一样的组,那之后调整就可以出问题

3.选择排序:不稳

3 3  1  1

假设原本是这样的,将1调整到第一位的时候,原本第一位的3会来到第三位,这样就会出问题

4.堆排序:不稳

堆排序建大堆小堆直接就乱了

5.冒泡排序:稳

每次都只是交换,前后位置还是不变的

6.快速排序:不稳

每次分割一半,兴许哪一次就出现问题

7.归并排序:稳(不稳)

如果两数一样时都放第一个数组元素,那它就是稳的,如果放第二个数组,那就是不稳的

8.计数排序:不稳

它只管计数,然后放回去,不会管先放的是哪个

【排序】八种常用排序相关推荐

  1. 八种常用排序算法参考

    写在前面: 因为网络上有很多篇讲排序算法的,所以这里就不详细讲了,只作为参考和自己查阅 当然了,虽然篇幅也会短很多,但部分重点和要点还在 八种排序算法分别是: ①选择排序: ②冒泡排序: ③插入排序: ...

  2. 排序 八种经典排序算法

    排序(Sorting) 是计算机程序设计中的一种重要操作,它的功能是将一个数据元素(或记录)的任意序列,重新排列成一个关键字有序的序列. 我整理了以前自己所写的一些排序算法结合网上的一些资料,共介绍8 ...

  3. [转载] java实现四种常用排序算法

    参考链接: 用Java排序 四种常用排序算法 ##注:从小到大排 ##冒泡排序## 特点:效率低,实现简单 思想:每一趟将待排序序列中最大元素移到最后,剩下的为新的待排序序列,重复上述步骤直到排完所有 ...

  4. c语言的5种常用排序方法

    c语言的5种常用排序算法 1.冒泡排序(最常用) 冒泡排序是最简单的排序方法:原理是:从左到右,相邻元素进行比较.每次比较一轮,就会找到序列中最大的一个或最小的一个.这个数就会从序列的最右边冒出来.( ...

  5. 八种常用的排序算法(转)

    下面要讲到的8种排序都属于内部排序,既在内存中完成,主要从理论原理方面来分析的.    插入排序 ①直接插入排序 例:六个数12 15 9 20  6 31 24 用直接插入排序,如下图: 思路: 第 ...

  6. 10种常用排序算法实现

    在使用VBA进行写程序时,经常会做排序,下面将会给出一些常用的排序算法的实现,方便大家写程序参考,若代码中出现了错误,欢迎高手指正. 主要算法有: 1.(冒泡排序)Bubble sort 2.(选择排 ...

  7. 剖析八种经典排序算法

    排序(Sorting) 是计算机程序设计中的一种重要操作,它的功能是将一个数据元素(或记录)的任意序列,重新排列成一个关键字有序的序列. 我整理了以前自己所写的一些排序算法结合网上的一些资料,共介绍8 ...

  8. 视觉直观感受7种常用排序算法

    视觉直观感受若干常用排序算法 1 快速排序 介绍: 快速排序是由东尼·霍尔所发展的一种排序算法.在平均状况下,排序 n 个项目要Ο(n log n)次比较.在最坏状况下则需要Ο(n2)次比较,但这种状 ...

  9. 八种经典排序算法总结

    前言 算法和数据结构是一个程序员的内功,所以经常在一些笔试中都会要求手写一些简单的排序算法,以此考验面试者的编程水平.下面我就简单介绍八种常见的排序算法,一起学习一下. 一.冒泡排序 思路: 比较相邻 ...

最新文章

  1. EZBioCloud:16S和原核基因组物种注释和新种鉴定
  2. 洛谷P2904 [USACO08MAR]跨河River Crossing 动态规划
  3. 网站优化之如何才能防止域名被恶意指向?
  4. 20行python代码的入门级小游戏-用Python设计一个经典小游戏
  5. java web windows_Java Web服务器部署指南(windows版)
  6. C# 调用 Delphi Dll链接库方法及示例
  7. php定位和天气,基于thinkphp实现依据用户ip判断地理位置并提供对应天气信息的应用...
  8. java读c二进制文件_如何使用JAVA读取C / Matlab创建的二进制文件
  9. 会计云课堂实名认证后怎么更改_离职了,税务局的会计信息还是我,老板就不更改,怎么办?...
  10. 高性能队列--Disruptor
  11. each 数据获取attr_Python数据分析 — 基于RFM的精细化用户分层
  12. maven(11)-聚合多模块
  13. 小程序坑 redirectTo 计时器 setInterval clearInterval
  14. android ram压力测试,android用memtester内存压力测试
  15. LintCode 38: Search a 2D Matrix II
  16. MATLAB 插值放大
  17. CC00075.bigdatajava——|Java循环结构.V14|——|Java.v14|while循环.v02|实现调和数列累加和|
  18. 图片分享和加载失败的原因之一
  19. matlab 变量的定义变量名称,matlab定义变量名
  20. Verilog学习笔记-——Verilog模块例化

热门文章

  1. npm使用过程中的一些错误解决办法及npm常用命令
  2. Intel迅盘应用从入门到精通
  3. 我叫张强,somnus
  4. python爬取看雪论坛的所有主题帖的回复消息
  5. 贪心算法 | 最优装载问题——加勒比海盗船
  6. PDF怎么编辑修改?如何编辑PDF的内容?
  7. 使用scrapy框架爬取斗鱼图片
  8. Spark-RDD实战影评数据分析一
  9. Linux平台C++ 实现毫秒/微妙级时间获取或者延时
  10. MODBUS-RTU数据帧格式、报文解析