1.
Ques:简单介绍选择排序
选择排序通过在每一轮循环中选择出极值,然后将之与未排序好区域的某个端点作交换,完成一次排序。
比如,第一轮选出最小值,此时的未排序区是0~n-1,则将这个最小值与0号数组元素作交换,完成排序,以此类推,外循环n次之后完成排序。
中间变量:保存每次排序最小值的temp,最小值的索引index。
2.
Ques:简单介绍插入排序
对给定的一组记录,初始时设定第一个记录为已排序序列,其余记录为无序序列,然后从第二个记录开始,依次插入到有序序列的相应位置。当最后一个无序序列插入完成时,完成排序。
比较发生在待插入元素判断自己的位置时与已排序序列的元素之间的比较。
3.
Ques:简单介绍冒泡排序
冒泡排序的特点是元素往上升,表现在算法上,则是在第k次循环时,将还未排好序的元素从左到右开始两两比较,保证两者间大的在右边,若是大的在右边则进行一次交换,这样当未排序的元素都完成比较之后,未排序的元素里的最大值就已经上升到最右边了,这个最大值就完成了排序,随后对剩下的元素重复操作,直到记录只剩一个为止。
4.
Ques:简单介绍归并排序
用到递归与分治,将序列划分成为越来越小的半子表,再对半子表排序,最后将拍好序的半子表合并成越来越大的有序序列。
模拟对话:
我一般介绍归并排序,还会附上一个例子,因为归并的思想说起来很简单,就是将之不断二分成小的子表,然后对子表排序,再进行合并,这样其实很抽象。在具体实现上其实才更能体现递归与分支的思想。
比如,有1~8个元素,那么我们从递归的底层说起,将他们不断二分之后,会变成1,2,3,……8个单独的序列,这序列是定义在我们心里的,实际上他们仍然还是在数组里一动不动,那么是怎么把这个抽象出来的子序列合并的呢,操作起来是,将1与2号元素额外开辟两个数组保存,将这两个数组看成子序列,然后对这两个子序列进行二路归并,排序到真实数组的1,2号位上。
那么3,4号,5,6号元素,7,8号元素也是同样的道理,这样就完成了最底层的子表的排序,再上一层的子序列,就变成了1,2。3,4……并且,这四个子表的序列都是经过二路归并是有序的,接下来就是对这四个子表,两两进行二路归并,最后变成两个有序子表,再经过一次二路归并,就得到了结果。
这是底层递归回来的过程,那么递归函数的写法就是先分后合,分是递归调用自身,合是另写一个函数,用以将子序列合并,具体实现中,只要明白一个中间量其实就很容易了,那个中间量,就是分合子表时,给的首尾序号的平均值,从首序号到这个中间量,就是划分的左子表,中间量到尾序号则是划分的右子表,在二路归并确定是哪两个数组归并时,用得就是这两个子表,这就完成了抽象的分与合的过程。
现场实现:
⑴.记住递归的结构
public void MergeSort(int[] arr,int start,int end)
{
if(start<end)
{
int mid = (start+end)/2;
MergeSort(arr,start,mid);
MergeSort(arr,mid+1,end);
Merge(arr,start,mid,end);
}
}
⑵实现二路归并合并子表的Merge()
public void Merge(int[] arr,int start,int mid,int end)
{
if(start>=end)
return ;
//先做个判断,如果是单个元素序列,直接返回
//复制数组序列从start~mid的元素到左子表
//复制数组序列从mid+1~end的元素到右子表
//左右子表进行二路归并将真实数组的start~end排好序
}
5.
Ques:简单介绍快速排序
快排采用分治,我的理解是,在找到一个标杆值,这个标杆值满足的条件是,在它左边的值全部比它小,在它右边的值全部比它大,找到这个值后,再对两边的部分继续进行上述操作。
因为这个标杆值其实就是排好序后,该元素所在的位置,所以确定标杆值就是确定元素位置,而不断分解到小的子表后,当只有两个元素时,确定好一个值的位置,也就完成了这两个元素的排序,这样,实际上是对所有区间都求好了标杆值,因此完成排序。
重点:如何找到标杆值
一般是把第一个记录当做标值,然后找它的位置,先用index记录下这个值,然后开始查找。
令j=end。从右边开始找,有a[j]小于index的话,交换a[i],a[j]。此时标值移到a[j],a[i]已在指定区,i++;
然后从i开始,从左往右找,有a[i]大于index的话,交换a[i],a[j]。此时标值又回到a[i],a[j]在指定区,j--;
重复上述操作,并且一直要保证i<j。
当i=j的时候,此时的a[i]或说a[j]就是标值,并且已经在中间位置了。
实现:
单向交换实现
public static void sort(int arr[],int start,int end)
{
int i = start;
int j = end;
while(i<j) //如果发生了i=j,就已经保证了对任意k,k<i时,a[k]<=a[i],且k>i时,a[k]>=a[i]
{
while(i<j&&arr[i]<arr[j]) j--; //找到一个arr[j]<=index结束
if(i<j) //如果此时i<j,证明找到的arr[j]不是arr[i],所以交换,标值变成arr[j]
{ swap(arr,i,j);
i++; }
while(i<j&&arr[i]<arr[j]) i++; //找到一个arr[i]>=index结束
if(i<j) //如果此时i<j,证明找到的arr[i]不是arr[j],所以交换,标值又变成arr[i]
{ swap(arr,i,j)
j--; }
}
if(i-1>start) sort(arr,start,i-1);
if(end>i+1) sort(arr,i+1,end);
}
双向交换实现,不过要注意一些细节
public static void sort(int arr[],int start,int end)
{
int i = start+1;
int j = end;
int index = arr[start];
while(i<j)
{
while(arr[j]>index) j--; //找到j使得arr[j]<=index
while(arr[i]<index&&i<j) i++; //找到i使得arr[i]>=index
if(i>=j) break; //两种情况,1.j=start,则实际arr[start]是最小值 2.i=j,以选出小于arr[start]的最右边的值
if(i<j) //i<j,则两边都找到了arr[i],arr[j],交换
{
swap(arr,i,j);
}
}
swap(arr,j,start); //最后一定是在break处跳出,交换arr[j]与arr[start]两种情况都能收尾
if(i-1>start) sort(arr,start,i-1);
if(end>i+1) sort(arr,i+1,end);
}
6.
Ques:简单介绍希尔排序
希尔排序又称缩小增量排序,是插排的一种,原理是先将待排序的数组元素分成多个子序列,可以将这些子序列理解为序号成公差不同的等差数列,然后对这些序列完成插入排序,再缩小公差重复操作,直到最后公差为1,实际上就是再进行插入排序,但此时元素已经基本有序,因为在公差很大的情况下,通过跳跃式的移动,使得比较与交换的次数减少了很多,所以可以实现效率的提升。
实现:
把握好三层循环的初始h,i,j到底是什么意思,可以简单的实现。
h是公差,可以取length/2直到1.也可以自己指定,最后有个1就行。
h一定的情况下,0~h-1分别是这些数列的第一个元素,那么h~len-1就是可以并且需要插入到相应数列里的元素,i负责遍历它们
a[i]是需要插入到相应数组的元素,那么j负责将之与其对应的数列比较,执行插入操作,a[i]所在的数组序列应该为i,i-h,i-2h……
public static void shellSort(int arr[])
{
int length = arr.length;
int i,j,h;
for(h=length/2;h>0;h=h/2)
{
for(i=h;i<length;i++)
{
int temp = arr[i];
for(j=i-h;j>=0;j-=h) //插入a[i]
{
if(arr[j]>temp)
arr[j+h]=arr[j];
else
break;
}
arr[j+h]=temp;
}
}
}
7.
Ques:简单介绍堆排序