碎碎念:
记得当初第一年的时候、接触算法、有那么两个视频、跳舞的、讲的是冒泡排序跟选择排序、当时看了好多遍最终懂了、这次多了一些算法、学起来也还好吧、咱是有基础的人、找到了曾经的视频、有的就发了、没找到的就没法、事实上算法并不难、绕绕就明确了、先别看代码- -
思维导图
插入排序
从头到尾巴、从第二个開始、向左进行插入、这里说的插入是指作比較、直到比較出比自己小的就插入到他的前面。
样例
1 7 4 8 6 5
插入排序
[1]7 4 8 6 5
[1 7] 4 8 6 5
[1 4 7] 8 6 5
[1 4 7 8 ] 6 5
[1 4 6 7 8 ] 5
[1 4 5 6 7 8 ]
特性
算法是稳定的、时间复杂度为O(n2)、空间复杂度为O(1)、须要一个辅助的空间变量
代码(java)
<span style="font-size:18px;">// insert_sort
publicint[] insert_sort(int[] arr) {
int[] intArr = arr;
int i, j, key;
for (j = 1; j < intArr.length; j++) {
key = intArr[j];
i = j - 1;
while (i >= 0 && intArr[i] > key) {
intArr[j] = intArr[i];
i--;
}
intArr[i + 1] = key;
}
return intArr;
}</span>
小编:咳咳咳、这次也自称小编了、事实上插入排序真的没啥- -、就是一个个往有序序列里面插入新的数值。
视频(插入)
交换排序
交换排序事实上就是两个值相互比較的思想、假设后面的值比前面的小、就交换位置(从小到大排序)、交换排序一般有冒泡排序、高速排序两种。
冒泡排序
第一次听说这个算法就想到了儿时家里养的金鱼、经常看它吐泡泡、(尽管不久它就不在了)、可是思想非常明显、那就是气泡在水里会上浮、所谓的冒泡排序就是从头到位、依次两个值做比較、假设后面的值比前面小、两个值就交换、每次都能够交换出一个’最大值‘,就好像大泡泡上浮一样。
样例(相邻的两个数交换、每循环一次交换就能找出一个最大的)
特性:时间复杂度为O(n2)是稳定的算法、可是数据大的时候不建议使用。
代码
<span style="font-size:18px;">void BubbleSort3(int a[], int n)
{
int j, k;
int flag;
flag = n;
while (flag > 0)
{
k = flag;
flag = 0;
for (j = 1; j < k; j++)
if (a[j - 1] > a[j])
{
Swap(a[j - 1], a[j]);
flag = j;
}
}
}</span>
视频(冒泡)
高速排序
事实上是冒泡排序的一种改进、取一个键值、然后与其它值相比較、比键值大的放后面键值小的放前面(交换)、循环一次的效果就是比键值大的都在前面了、比键值小的都在后面了、然后再在前面那半取一个键值、循环上边步骤、不断划分、直到排序完毕。
样例:
特性:时间复杂度为O(nlog2n)、不稳定!平均时间最佳。最坏情况近似O(n2)
代码
<span style="font-size:18px;">#include<iostream>
using namespace std;
void quickSort(int a[],int,int);
int main()
{
int array[]={34,65,12,43,67,5,78,10,3,70},k;
int len=sizeof(array)/sizeof(int);
cout<<"The orginal arrayare:"<<endl;
for(k=0;k<len;k++)
cout<<array[k]<<",";
cout<<endl;
quickSort(array,0,len-1);
cout<<"The sorted arrayare:"<<endl;
for(k=0;k<len;k++)
cout<<array[k]<<",";
cout<<endl;
system("pause");
return 0;
}
void quickSort(int s[], int l, int r)
{
if (l< r)
{
int i = l, j = r, x = s[l];
while (i < j)
{
while(i < j && s[j]>= x) // 从右向左找第一个小于x的数
j--;
if(i < j)
s[i++] = s[j];
while(i < j && s[i]< x) // 从左向右找第一个大于等于x的数
i++;
if(i < j)
s[j--] = s[i];
}
s[i] = x;
quickSort(s, l, i - 1); // 递归调用
quickSort(s, i + 1, r);
}
} </span>
视频(高速)
选择排序
直接选择排序
这个真的简单的不想说了= = 、有一行数、每次都选择一个最小的出来、如图
<span style="font-size:18px;">//为了使用Random类,须要增加例如以下这行:
import java.util.*;
/**
* 直接选择排序算法的Java实现。<br/>
* 1:从a[0]-a[N-1]中选出最小的数据,然后与a[0]交换位置<br/>
* 2:从a[1]-a[N-1]中选出最小的数据,然后与a[1]交换位置(第1步结束后a[0]就是N个数的最小值)<br/>
* 3:从a[2]-a[N-1]中选出最小的数据。然后与a[2]交换位置(第2步结束后a[1]就是N-1个数的最小值)<br/>
* 以此类推。N-1次排序后,待排数据就已经依照从小到大的顺序排列了。<br/>
* 此代码作为课件提供给学生參考,在学完数组、循环、推断后练习。<br/>
* @author luo_wenqiang@126点com
* @version 1.0.0
*/
public class 直接选择排序
{
public static void main(String[] args)
{
//声明一个数组
int[] array = new int[10];
//为这个数组随机填入整型数字
Random random = new Random();
for (int i = 0; i < array.length ; i++)
{
array[i] = random.nextInt(500);
}
System.out.print("原始数组 :");
System.out.println(Arrays.toString(array));
/****************************************
以下開始正式的“直接选择排序”算法
直接选择排序的关键:
1:从a[0]-a[N-1]中选出最小的数据,然后与a[0]交换位置
2:从a[1]-a[N-1]中选出最小的数据,然后与a[1]交换位置(第1步结束后a[0]就是N个数的最小值)
3:从a[2]-a[N-1]中选出最小的数据,然后与a[2]交换位置(第2步结束后a[1]就是N-1个数的最小值)
以此类推。N-1次排序后。待排数据就已经依照从小到大的顺序排列了。
****************************************/ //N个数组元素,就须要循环N轮 for(int i = 0; i < array.length; i++){ //最小数的索引,该索引每次都依据外层循环的计数器来认为初始值。
int minIndex = i; for (int j = i; j < (array.length); j++) { //依据最小数的索引,推断当前这个数是否小于最小数。
//假设小于。则把当前数的索引作为最小数的索引。
//否则不处理。 if(array[minIndex] > array[j]){ minIndex = j; } //直到循环完毕的时候。minIndex肯定就是当前这轮循环中。最小的那个。 } //System.out.print(i + "轮。最小数" + array[minIndex] + "。"); //System.out.print("原索引" + minIndex + ",新索引" + i); //得到最小数的索引后。把该索引相应的值放到最左边,而且把最左边的值放到索引所在的位置. //最左边的值 int temp = array[i]; //把最小数索引相应的值放到最左边 array[i] = array[minIndex]; //把原来最左边相应的值放到最小数索引所在的位置 array[minIndex] = temp; System.out.println(String.format("%2s",(i + 1)) + "轮排序后:" + Arrays.toString(array)); } } }</span>
我次………………复制百度的代码真不少 = =
堆排序
简单的了解下堆、堆分最大堆和最小堆、最大堆跟比也子节点大、最小堆相反
最大堆和最小堆
假设从小到大用堆排序、每次都把最小堆的根输出、然后用堆的最后一层最右边的叶子节点补上去、然后进行堆排序(从节点数除以2的根開始排序)、选出最小根、输出、依次这样直到堆的数都输出完。
这里最重点的事实上是堆排序
推荐一篇博客吧
http://blog.csdn.net/genios/article/details/8157031
归并
二路归并排序
把每两个数分成一组、相比較、假设顺序不正确就交换顺出、循环一次之后、把两个分组合成一个分组、这时候这个分组有四个数、然后进行排序、依此循环、最总合并成一个组、就是按从大到小排序的了、发张图吧= =说的不太清。
代码
package algorithm;
public class MergeSort {
// private static long sum = 0;
/**
* <pre>
* 二路归并
* 原理:将两个有序表合并和一个有序表
* </pre>
*
* @param a
* @param s
* 第一个有序表的起始下标
* @param m
* 第二个有序表的起始下标
* @param t
* 第二个有序表的结束小标
*
*/
private static void merge(int[] a, int s, int m, int t) {
int[] tmp = new int[t - s + 1];
int i = s, j = m, k = 0;
while (i < m && j <= t) {
if (a[i] <= a[j]) {
tmp[k] = a[i];
k++;
i++;
} else {
tmp[k] = a[j];
j++;
k++;
}
}
while (i < m) {
tmp[k] = a[i];
i++;
k++;
}
while (j <= t) {
tmp[k] = a[j];
j++;
k++;
}
System.arraycopy(tmp, 0, a, s, tmp.length);
}
/**
*
* @param a
* @param s
* @param len
* 每次归并的有序集合的长度
*/
public static void mergeSort(int[] a, int s, int len) {
int size = a.length;
int mid = size / (len << 1);
int c = size & ((len << 1) - 1);
// -------归并到仅仅剩一个有序集合的时候结束算法-------//
if (mid == 0)
return;
// ------进行一趟归并排序-------//
for (int i = 0; i < mid; ++i) {
s = i * 2 * len;
merge(a, s, s + len, (len << 1) + s - 1);
}
// -------将剩下的数和倒数一个有序集合归并-------//
if (c != 0)
merge(a, size - c - 2 * len, size - c, size - 1);
// -------递归运行下一趟归并排序------//
mergeSort(a, 0, 2 * len);
}
public static void main(String[] args) {
int[] a = new int[] { 4, 3, 6, 1, 2, 5 };
mergeSort(a, 0, 1);
for (int i = 0; i < a.length; ++i) {
System.out.print(a[i] + " ");
}
}
}
算法复杂度与特性总结
排序算法 | 时间 | 特性 |
插入排序(插入) | O(n2) | 记录少适用、记录多不适用 |
冒泡排序(交换) | O(n2) | 稳定! |
高速排序(交换) | O(nlog2n) | 不稳定! 平均时间最佳! 最坏情况近似 O(n2) |
直接选择(选择) | O(n2) | 简单、easy实现、不适合N较大的情况 |
堆排序(选择) | O(n log2n) | 不适用排序记录较少、适合较多记录 |
有序序列合并(归并) | O(n-h+1) |
|
二路归并排序(归并) | O(n log2n) | N较大时、归并排序时间性能优于堆排序、可是所需储存量较大 |
|
|
|
总结:
这些算法预计以后用都是别人封装好的、拿来直接用即可、可是用东西、要知道他的特性、数多的时候用哪个?数少的时候用哪个、什么时候用、事实上算法也就那么回事、不要想太复杂、考试的话、时间复杂度主要考考、空间复杂度非常少考、特性要考的、会出给一列数、让你用算法排序、把步骤写出来。
————————————高大上的算法————————————-
———————chenchen————————