1> 插入排序:
基本思想: 把需要排序的集合分为两部分,一部分是排序好的,一部分未排序的。就像打扑克一样,如果你习惯从左到右按从小到达的方式排列,开始都背面盖着放在桌上,然后抓起一张,抓第二张时,先和手上的第一张对比,如果点数大于第一张,那就把它插到第一张的右边。剩下桌上的牌都按照这个方式去处理。
实际上,在用java数组处理的时候,还是和玩扑克是有区别的。扑克的左右没有边界限制,而实际数组有边界限制,所以,需要考虑到边界的问题,所以最好是从右到左查找过去,不会产生越界的问题。
------------------用java数组进行实现------------------------
从右到左查找
---------------------------code-begin-----------------------
public static int[] insertSort(int[] rawArr) {
// 常识性的判断,不要没有牌或者牌只有1张
if (rawArr == null || rawArr.length < 2) {
return rawArr;
}
//从第二个数开始,第一张已经抓在手上了
for(int i = 1 ; i < rawArr.length ; i++ ) {
int j = i - 1 ; //对比手上的牌,最右边的那张
int insertVal = rawArr[i] ; //待插入的牌
while(j > -1 && rawArr[j] > insertVal) { //如果牌比待插入的大,往左边继续看
rawArr[j+1] = rawArr[j]; //把牌向右挪一位
j-- ; //检查左边的牌
}
rawArr[j+1] = insertVal ; //最后,把牌插入正确的位置
//到下一个循环,也就是下一张没上来的牌。
}
return rawArr ;
}
----------------------------code-end------------------------
2> 冒泡排序:
基本思想:
可以想想成数组的样子是从上到下的。如果排序是从大到小,那么就是从底部开始两两对比,哪个数大就放到上面。这样经过第一轮的对比,最大的数就会“浮”到最上面,也就是第一个位置。第二轮的时候,最上面的数就不用对比了,第二轮完毕之后,倒数第二大的数就会“浮”到倒数第二个位置。依次类推,最后循环完,就会按从大到小的顺序排列了。
-------------------------code-begin-------------------------
public int[] popUpSort(int[] rawArr) {
if(rawArr == null || rawArr.length < 2) {
return rawArr ;
}
//有n个数,就是运行n-1次,最后一个数就不用比对了
for(int i = 1 ; i < rawArr.length ; i++) {
//两个两个对比,从下往上,到排序完的那个数为止(不包含)
for(int j = 0 ; j < rawArr.length - i ; j ++) {
if(rawArr[j] < rawArr[j+1]) {
int tmp = rawArr[j];
rawArr[j] = rawArr[j+1];
rawArr[j+1] = tmp ;
}
}
}
return rawArr ;
}
-------------------------code-end---------------------------
3> 归并排序
基本思想:
一个无序的数组,假如要从小到大进行排序。先分割成两部分,然后每部分再进行分割,直到分割的部分只有一个元素时,就认为它是有序的。这时候,再进行合并,合并的流程就是新建一个临时数组,长度是两个子数组长度的和。然后分别扫描两个子数组(a和b),如果a[0]小于b[0],那就把a[0]先加到临时数组中(反之,就是把b[0]先加到临时数组中),然后a数组向前移动一位,然后a[1]再与b[0]比较,比较小的就加到临时数组中。以此类推,当有一个数组添加完毕之后,而另一个数组有所剩余,就把剩下的元素都加到临时数组中,这样就完成了排序。然后递归的返回,然后合并,最终就得到整个数组的排序后的数组。
-------------------------code-begin-------------------------
public int[] mergeSort(int[] rawArr) {
if(rawArr == null && rawArr.length < 2) {
return rawArr;
}
return merge(rawArr);
}
private int[] merge(int[] slice) {
//只有一个元素,直接就是排序好的
if(slice.length == 1) {
return slice;
}
//切成两部分
int half = slice.length / 2 ;
int[] aArr = getSubArrayOf(slice,0,half);
int[] bArr = getSubArrayOf(slice,half,slice.length);
//递归调用,这样aArr和bArr就是排序好的了
aArr = merge(aArr) ;
bArr = merge(bArr) ;
//下面就进行合并
int aLength = aArr.length ;
int bLength = bArr.length ;
int totalLength = aLength + bLength ;
int[] mArr = new int[totalLength];
int i = 0 ;
int j = 0 ;
int k = 0 ;
//扫描两个子数组,根据条件进行排序
while(i < aLength && j < bLength) {
if(aArr[i] < bArr[j]) {
mArr[k++] = aArr[i++];
}else {
mArr[k++] = bArr[j++] ;
}
}
//如果是a数组剩余,就把剩下的加到父数组中
while(i < aLength) {
mArr[k++] = aArr[i++];
}
//如果是b数组剩余,就把剩下的加到父数组中
while( j < bLength) {
mArr[k++] = bArr[j++];
}
//合并好就返回
return mArr;
}
private int[] getSubArrayOf(int[] arr, int startIndex , int endIndex) {
if(endIndex < startIndex) {
return null;
}
int len = endIndex - startIndex ;
int[] newArr = new int[len];
for(int i = startIndex ; i < endIndex ; i++) {
newArr[i-startIndex] = arr[i];
}
return newArr;
}
-------------------------code-end---------------------------
4> 堆排序
堆是树状结构的,主要有两个特点:
1) 根节点的值最小(最大)
2)子树也是一个堆,称为最小堆(最大堆)
二叉堆是完全二叉树或者是近似完全二叉树来构造的堆。
还有其他“堆”(二项式堆,斐波纳契堆)
利用堆的结构,比如最小堆,那么根节点是当前的树状结构中值最小的元素。
那么,如果一组数要从小到大,先把它调节成一个最小堆,然后每次取它的根节点,然后删除根节点,再对剩下的树状结构进行调整,重新成为一个最小堆。然后再取根节点,这样循环的做下去,这样,最后元素都取完了,那么也就把数据都从小到大排序好了。
这样,需要两个步骤对排序进行辅助。
1)根节点删除
2)调整成堆
按照数组的方式存储堆,那么节点之间的关系为:
节点位置为i。那么父节点位置为 i-1 / 2
两个子节点的位置为 2*i + 1 与 2*i + 2
如果是一个数组,要使用堆的性质进行排序。那么就是:
1)调整成堆
2)把根节点a[0]和最后一个节点a[n-1]对调。
然后再对a[0]到a[n-2]进行恢复堆,然后再把a[0]和a[n-2]进行对调。
循环下去,直到a[0],这样就排好了。
5> 快速排序
----------------------------------------------------
http://www.cnblogs.com/surgewong/p/3381438.html
----------------------------------------------------
快速排序的基本思想: 通过一次循环,把需要排序的元素分割成两部分A和B,长度不一定相等,但其中A中任何元素的值比B中任何元素的值都要小。
然后再递归调用,分别再对A和B进行切割,分别分成两部分,也是一部分中的元素值比另一部分都小。循环分割,到只有一个数,那么每段都是排序好了。
然后再递归返回,由于每一段都是已经排序好的,那么返回的时候,两段就不需要重新进行比较,直接连接起来就是排序好的。
那么,具体怎么在一次循环中就把数据分割成满足要求的两部分呢?
先选一个值x,然后分别从数组的两端进行扫描,比这个数小的就放到这个数的左边,比这个数大的就放到这个数的右边。
以下为例:
0 1 2 3 4 5 6 7
--------------------------------------------
| 46 | 30 | 82 | 90 | 56 | 17 | 95 | 15 |
--------------------------------------------
i=0 j=7
选第一个数 46 为x , 然后开始比较, a[j] = 15 < 46 ,那么就交换两个数的位置,同时i向前移动一位。
0 1 2 3 4 5 6 7
--------------------------------------------
| 15 | 30 | 82 | 90 | 56 | 17 | 95 | 46 |
--------------------------------------------
i=1 j=7
然后再比较, a[i] = 30 < 46 ,那么不动,i再移动一位
0 1 2 3 4 5 6 7
--------------------------------------------
| 15 | 30 | 82 | 90 | 56 | 17 | 95 | 46 |
--------------------------------------------
i=2 j=7
然后再比较,a[i] = 82 > 46 ,那么交换两者的位置,然后j向后移动一位。
0 1 2 3 4 5 6 7
--------------------------------------------
| 15 | 30 | 46 | 90 | 56 | 17 | 95 | 82 |
--------------------------------------------
i=2 j=6
然后比较 a[j] = 82 > 46 , 不动,j再向后移动一位
0 1 2 3 4 5 6 7
--------------------------------------------
| 15 | 30 | 46 | 90 | 56 | 17 | 95 | 82 |
--------------------------------------------
i=2 j=5
然后再比较, a[j] = 17 < 46 ,两者交换,i向前移动一位
0 1 2 3 4 5 6 7
--------------------------------------------
| 15 | 30 | 17 | 90 | 56 | 46 | 95 | 82 |
--------------------------------------------
i=3 j=5
再比较 a[i] = 90 > 46 ,两者交换,j向后移动一位
0 1 2 3 4 5 6 7
--------------------------------------------
| 15 | 30 | 17 | 46 | 56 | 90 | 95 | 82 |
--------------------------------------------
i=3 j=4
再比较 a[j] = 56 > 46 ,不交换,j向后移动一位
0 1 2 3 4 5 6 7
--------------------------------------------
| 15 | 30 | 17 | 46 | 56 | 90 | 95 | 82 |
--------------------------------------------
i=j=3
此时发现i=j=3,这时候,此次分割结束。
这样,数组被分割成[0-2][3][4-7]三个区间,然后再递归的对[0-2]和[4-7]按照以上方式进行分割。
最后分割成一个个数之后再分别合并起来,组成一个有序的序列。
-------------------------code-begin-------------------------
private void quick_sort(int[] rawArr,int left , int right) {
if(left < right) {
int i = left ;
int j = right ;
int x = rawArr[i];
while( i < j ) {
while(i < j && rawArr[j] < x) {
j-- ;
}
if(i < j) {
rawArr[i++] = rawArr[j] ;
}
while(i < j && rawArr[i] >= x) {
i++ ;
}
if(i < j) {
rawArr[j--] = rawArr[i];
}
}
rawArr[i] = x;
quick_sort(rawArr,left,i-1);
quick_sort(rawArr,i+1,right);
}
-------------------------code-end---------------------------
6> shell排序
通过不断“对折”,然后对各个分组进行“插入排序”。
例如以下数据:
有8个数,第一次先取 gap = 4
0 1 2 3 4 5 6 7
--------------------------------------------
| 46 | 30 | 82 | 90 | 56 | 17 | 95 | 15 |
--------------------------------------------
这样数据就分为了(0,4)(1,5)(2,6)(3,7)总共4组。 然后对每组元素分别进行“插入排序”。
0 1 2 3 4 5 6 7
--------------------------------------------
| 46 | 17 | 82 | 15 | 56 | 30 | 95 | 90 |
-----------------------------------------
然后再“对折”,gap = gap / 2 = 2。这样分为了2组。
(0,2,4,6)(1,3,5,7) ,然后再对每组进行“插入排序”。
0 1 2 3 4 5 6 7
--------------------------------------------
| 46 | 15 | 56 | 17 | 82 | 30 | 95 | 90 |
--------------------------------------------
然后再“对折”,gap= gap / 2 = 1 这样就只有1组。(0,1,2,3,4,5,6,7) 再进行插入排序。
0 1 2 3 4 5 6 7
--------------------------------------------
| 15 | 17 | 30 | 46 | 56 | 82 | 90 | 95 |
--------------------------------------------
然后再对折 gap = gap / 2 = 0 结束。
-------------------------code-begin-------------------------
for(gap = n / 2 ; gap > 0 ; gap /= 2) { // count of split
for(int i = 0 ; i < gap ; i++) { // group size
for(int j = i + gap ; j < n ; j += gap) {
if(rawArr[j] < rawArr[ j- gap ]) {
int insertVal = rawArr[j] ;
int k = j - gap ;
while(k >= 0 && rawArr[k] > insertVal) {
rawArr[k + gap] = rawArr[k] ;
k -= gap ;
}
rawArr[k + gap] = insertVal ;
}
}
}
}
-------------------------code-end---------------------------