上篇写到利用二分查找在有序数组中查找某一特定值,然后当时想了个问题,为什么是数组而不是链表呢,这就要讲讲两者的区别了。
数组的元素带编号,一般从0开始,元素的位置被称为索引。数组可以随机地读取元素(因为元素索引),查找效率很高,可以迅速找到任何元素,它的读数操作的运行时间只有O(1)。与极快的查找速度不同,数组的插入操作和删除操作的运行时间都是O(n),是因为在插入时,插入位置后的元素都需要向后移,给待插入元素腾位置;而删除某一元素时,需要将待删除的位置后的所有元素都往前移,把前面待删除元素给挤出去。同时,一个数组的所有元素在内存中的存储位置都是相连的,如果需要添加位置但相连位置已被占用,就需要请求计算机重新分配可以容纳该数组的内存,再把数组进行移动,听起来就比较复杂。
链表与数组不同,它的元素可以存储在计算机内存的任何地方,是因为链表的每个元素都存储了下一个元素的地址,从而使一系列随机的内存地址串联在一起。但这也带来一定的麻烦,因为元素并非靠在一起,就无法迅速查找特定元素,必须先访问第一个元素以获得第二个元素的地址,然后再访问第二个元素以获得第三个元素的地址,以此类推,所以其读数操作运行时间是O(n)。而插入和删除操作对于链表来说就有很高的效率:只需要修改它前面那个元素指向的地址。
基于链表只支持顺序访问,而数组在支持顺序访问的同时也支持随机访问,因此二分查找更适合用数组来做。
今天训练的算法是选择排序,也就是每次都去数组进行比较,依次选出第一大、第二大、第三大······(第一小、第二小、第三小······)进行排序,运行时间是O()。
package algorithm;
import java.util.List;
public class SelectionSort {
public static void main(String[] args){
System.out.println("选择排序练习");
int[] arr={7,3,4,2,9,45,34,23};
boolean [] flag=new boolean[arr.length];//已被选择的元素下标的标记
for(int i=0;i<arr.length;i++){
flag[i]=false;
}
int [] newarr=selectionSort(arr,flag);
for (int i = 0;i<arr.length;i++){
System.out.println(newarr[i]);
}
}
private static int findSmallest(int [] arr,boolean [] flag){//查找最小元素的索引
int smallest=0 ;
int smallest_index=0; ;
for(int i=0;i<flag.length-1;i++){
if(flag[smallest_index]==true)
smallest_index+=1;
}
smallest=arr[smallest_index];
for (int i = 0;i < arr.length; i++){
if(arr[i] < smallest&&flag[i]==false){
smallest = arr[i];
smallest_index = i;
}
}
return smallest_index;
}
private static int [] selectionSort(int [] arr,boolean [] flag){//对数组进行排序
int [] newarr = new int[arr.length];
int smallest_index;
for(int i = 0;i <arr.length;i++){
smallest_index=findSmallest(arr,flag);
if(flag[smallest_index]==false){
newarr[i]=arr[smallest_index];
flag[smallest_index]=true;
}
}
return newarr;
}
}