三种简单排序:冒泡排序、选择排序、插入排序
三种算法都包括两个步骤:1.比较两个数据项;2.交换两个数据项,或复制其中一项。
这里按例子来:把 ArrayList 中的值按从小到大的顺序打印出来
冒泡排序:
1.相邻两数进行比较,若左边数大则两数交换位置;再向右移动一个位置,比较下两个数,如此循环。最大的数会“冒泡”到数组的顶端。
2.冒泡排序代码
public void BubbleSort(){
for(int p=0;p < arraylist.size()-1;p++){
for(int q=0;q <arraylist.size()-1-p;q++){
if(arraylist.get(q)>arraylist.get(q+1)){
int temp = arraylist.get(q);
arraylist.set(q,arraylist.get(q+1));
arraylist.set(q+1,temp);
}
}
}
System.out.println(arraylist); //按从小到大的顺序打印出数字
}
3.冒泡排序的不变性(算法执行时不变的条件):每一趟排序完,“冒泡”到数组顶端的数据为有序的。
4.冒泡排序的效率:
O(N2)时间级别
比较次数:优化情况下为N*(N-1)/2 (约为N2/2);未优化情况就是N2
交换次数:数据随机为N2/4(大概有一半需交换);最坏情况为N2/2(即逆序时每次比较都需要交换)
选择排序
1.从最左边(0号位置)开始,把所有数据扫描一遍从中挑出最小的放最左边(0号位置);再从1号位置开始扫描寻找最小的放1号位,如此循环。
相比冒泡排序减交换次数。
2.选择排序代码:
public void selectionSort(){
for(int p=0;p < arraylist.size()-1;p++){
for(int q=p+1;q<arraylist.size();q++){
if(arraylist.get(p)>arraylist.get(q)) {
int temp = arraylist.get(p);
arraylist.set(p, arraylist.get(q));
arraylist.set(q,temp);
}
}
}
System.out.println(ReadAFile.arraylist); //按从小到大的顺序打印出数字
}
3.选择排序的不变性:每次扫描完放在左边的数据是有序的。
4.选择排序的效率:
O(N2)时间级别
比较次数:与冒泡排序一样,优化情况下为N*(N-1)/2 (约为N2/2)
交换次数:比冒泡排序交换次数少
插入排序
1.一般用在数据局部有序时。数据中间有一个被标记的,它的左边已经局部有序,被标记和它右边的是未被排序的;然后要做的是在局部有序组中适当位置插入被标记数据,为了提供移动所需空间,先让被标记数据被储存在一个临时变量中;然后开始移动已经排过序的数据,当把最后一个比被标记数据还大的数据移位之后,这个移动过程停止;最后一次移出的空位,就是被标记数据应该插入的位置。然后在右边未排序部分向右移动一个位置继续标记数据,重复循环。
一般情况下,比冒泡排序快一倍,比选择排序快一点。
2.插入排序代码:
public void insertionSort(){
for(int p=1;p < arraylist.size();p++) { //插入排序,标记了未排序部分的最左端数据
int temp = arraylist.get(p); //移除被标记数据,腾出移动空间
int q = p-1; //左移比较开始的位置
while(q >=0 && arraylist.get(q) > temp){
arraylist.set(q+1, arraylist.get(q));
q--;
}
arraylist.set(q+1,temp);
}
System.out.println(ReadAFile.arraylist); //按从小到大的顺序打印出数字
}
3.插入排序的不变性:在将被标记数据插入后,左边部分数据都是局部有序的。
4.插入排序的效率:
对于随机顺序数据需要O(N2)时间级别;基本有序数据只需要O(N)时间级别。
对于最坏情况,即逆序时,每次比较和移动都会执行,此时插入排序不比冒泡排序快。
稳定性
有些时候,排序要考虑数据拥有相同关键字的情况,则只需要算法对需要排序的数据进行排序,让不需要排序的数据保持原来顺序。满足这样要求的算法可称为稳定的算法。