排序算法总结及面试题

排序算法总览

排序大的分类可以分为两种:内排序和外排序。在排序过程中,全部记录存放在内存,则称为内排序,如果排序过程中需要使用外存,则称为外排序。下面讲的排序都是属于内排序。内排序有可以分为以下几类:

(1)、插入排序:直接插入排序、二分法插入排序、希尔排序。

(2)、选择排序:简单选择排序、堆排序。

(3)、交换排序:冒泡排序、快速排序。

(4)、归并排序

(5)、线性时间排序:计数排序、基数排序、桶排序

算法复杂度以及稳定性分析

外排序

外排序(External
sorting)是指能够处理极大量数据的排序算法。通常来说,外排序处理的数据不能一次装入内存,只能放在读写较慢的外存储器(通常是硬盘)上。外排序通常采用的是一种“排序-归并”的策略。在排序阶段,先读入能放在内存中的数据量,将其排序输出到一个临时文件,依次将待排序数据组织为多个有序的临时文件。然后在归并阶段将这些临时文件组合为一个大的有序文件,也即排序结果。

内排序

插入排序

直接插入排序

基本思想:每步将一个待排序的纪录,按其关键字的大小插入到已经排好序的有序数据中,直到全部插入完为止。

public static void insertSort(int[] arr){
	if(arr == null || arr.length <= 1) return;
	for(int i=1;i<arr.length ;i++){
		int p=i;
		int temp=arr[p];
		while(p>0&&arr[p-1]>temp){
			arr[p]=arr[p-1];
			p--;
		}
		arr[p]=temp;
	}
}

特征分析:

1、空间复杂度O(1)。最好时间复杂度O(n),最坏时间复杂度O(n^2),平均时间复杂度为O(n^2)。最好情况下(已有序),比较次数n-1,移动次数0,最坏情况,比较次数O(n^2),移动次数O(n^2)。

2、直接插入排序是稳定的。

使用场景:

适合少量数据的排序,或者数据基本已经有序的情况。

二分插入排序(折半插入)

直接插入排序算法在寻找插入位置是采用线性查找的方式,我们可以采用二分查找来确定插入位置从而减少比较次数。

public static void binaryInsertSort(int[] arr){
	if(arr == null || arr.length <= 1) return;
	for(int i=1;i<arr.length ;i++){
		int temp=arr[i];
		int start=0,end=i;
		while(start<end){
			int mid=start+(end-start)/2;
			if(arr[mid]<=temp){
				start=mid+1;
			}else{
				end=mid;
			}
		}
		int p=i;
		while(p>end){
			arr[p]=arr[p-1];
			p--;
		}
		arr[p]=temp;
	}
}

特征分析:

1、折半插入排序仅减少了关键字间的比较次数,而记录的移动次数不变。

使用场景:

1、如果元素的比较的操作比较耗时,可以对直接插入排序的性能进行提升。

链表的插入排序

由于链表不具有随机访问特性,因此不适用于折半插入排序,只适用于直接插入排序,每次从已排序数据表头开始查找插入位置。

public class ListNode{
	private int val;
	private ListNode next;
	public ListNode(int val){
		this.val=val;
	}
}
public static ListNode listInsertSort(ListNode head){
	ListNode myHead=new ListNode(-1);
	ListNode p=head,t,pre,post;
	while(p!=null){
		t=p;
		p=p.next;
		pre=myHead;
		post=myHead.next;
		while(post!=null&&post.val<=t.val){
			pre=pre.next;
			post=post.next;
		}
		t.next=post;
		pre.next=t;
	}
	return myHead.next;
}

希尔排序

基本思想:

直接插入排序中,如果元素X初始化时所处的位置为i,排序后所处位置为j,那么元素x必须要经过j-i-1(j>=i)次移动。而希尔排序中,我们先取一个小于n的整数d1作为第一个增量,把数据的全部记录分组。所有距离为d1的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量

di

=1(

di

<

di-1

…<d2<d1),即所有记录放在同一组中进行直接插入排序为止(这时候数组已经基本有序)。平均情况下,因为分组的增量>=1,元素X从初始化位置移动到最终位置所需要的次数比原来要小。

public static void shellSort(int[] arr){
	if(arr == null || arr.length <= 1) return;
	int gap=arr.length/2;
	while(gap>0){
		for(int i=1;i<arr.length ;i++){
			int temp=arr[i];
			int p=i;
			while(p>=gap&&arr[p-gap]>temp){
				arr[p]=arr[p-gap];
				p-=gap;
			}
			arr[p]=temp;
		}
		gap/=2;
	}
}

特征分析:

不需要大量的辅助空间,和归并排序一样容易实现。希尔排序是基于插入排序的一种算法,
在此算法基础之上增加了一个新的特性,提高了效率。希尔排序的时间复杂度与增量序列的选取有关,希尔排序时间复杂度的下界是n*log2n。希尔排序没有快速排序算法
O(n(logn)),因此中等大小规模表现良好,对规模非常大的数据排序不是最优选择。但是比O(

n^2

)复杂度的算法快得多。并且希尔排序非常容易实现,算法代码短而简单。 此外,希尔算法在最坏的情况下和平均情况下执行效率相差不是很多,与此同时快速排序在最坏的情况下执行的效率会非常差。专家们提倡,几乎任何排序工作在开始时都可以用希尔排序,若在实际使用中证明它不够快,再改成快速排序这样更高级的排序算法.
本质上讲,希尔排序算法是直接插入排序算法的一种改进,减少了其复制的次数,速度要快很多。
原因是,当n值很大时数据项每一趟排序需要的个数很少,但数据项的距离很长。当n值减小时每一趟需要移动的数据增多,此时已经接近于它们排序后的最终位置。
正是这两种情况的结合才使希尔排序效率比插入排序高很多。Shell算法的性能与所选取的分组长度序列有很大关系。只对特定的待排序记录序列,可以准确地估算关键词的比较次数和对象移动次数。想要弄清关键词比较次数和记录移动次数与增量选择之间的关系,并给出完整的数学分析,至今仍然是数学难题。

选择排序

简单选择排序

它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。

public static void simpleSelectSort(int[] arr){
	if(arr==null||arr.length<=1)
		return;
	for(int i=0;i<arr.length;i++){
		int start=i,minIndex=i;
		for(int j=i+1;j<arr.length;j++){
			if(arr[j]<arr[minIndex])
				minIndex=j;
		}
		int temp=arr[start];arr[start]=arr[minIndex];arr[minIndex]=temp;
	}
}

特征分析:

1、空间复杂度O(1),最好/最坏/平均时间复杂度都是O(n^2),比较次数O(n^2),移动次数O(n)。

2、选择排序是不稳定的排序方法(比如序列[5,
5, 3]第一次就将第一个[5]与[3]交换,导致第一个5挪动到第二个5后面)。

堆排序

堆分为大根堆和小根堆,是完全二叉树。大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]]
>= A[i]。在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。最小堆通常在构造优先队列时使用。

堆排序

基本思想:

首先通过自底向上的调整堆来建立大根对,然后依次将最大值a[0]与末尾元素交换并调整交换后的堆(大小减1)。

	//调整堆
	public static void adjustHeap(int[] arr,int size,int top){
	    while(top*2+1<=size-1){
	        int change=0;
	        if(top*2+1==size-1){//只有左子节点
	            change=top*2+1;
	            if(arr[top]>=arr[top*2+1]){
	                break;
	            }
	        }else{
	            change=arr[top*2+1]>arr[top*2+2]?top*2+1:top*2+2;
	            if(arr[top]>=arr[change]){
	                break;
	            }
	        }
	        int t=arr[top];arr[top]=arr[change];arr[change]=t;
	        top=change;
	    }
	}
	//建堆
	public static void buildHeap(int[] arr){
	    for(int top=(arr.length)/2;top>=0;top--){
	        adjustHeap(arr,arr.length,top);
	    }
	}
	//堆排序
	public static void heapSort(int[] arr){
	    buildHeap(arr);
	    for(int i:arr){
		    System.out.print(i+" ");
		}
		System.out.println();
	    for(int size=arr.length;size>=2;size--){
	        int t=arr[0];arr[0]=arr[size-1];arr[size-1]=t;
	        adjustHeap(arr,size-1,0);
	    }
	}

特征分析:

1、空间复杂度O(1),平均时间复杂度O(n log n),依次堆调整O(log n)——即堆的高度。由于建初始堆所需的比较次数较多,所以堆排序不适宜于记录数量较少的情况。

2、堆排序时不稳定的。

交换排序

冒泡排序

基本思想:

比较相邻的元素,如果前者比后者大,就交换他们两个,对从前往后对每一对相邻元素作同样的工作,这样一趟冒泡后,最后的元素就是最大的数。这样每一趟冒泡确定一个元素的位置,n趟后数组即有序。同样也可以从后往前冒泡,依次确定最小值。

	public static void bubbleSort(int[] arr){
	    for(int end=arr.length-1;end>0;end--){
	        boolean changed=false;
	        for(int index=0;index<end;index++){
	            if(arr[index]>arr[index+1]){
	                int t=arr[index+1];
	                arr[index+1]=arr[index];
	                arr[index]=t;
	                changed=true;
	            }
	        }
	        if(changed==false) return;
	    }
	}

特征分析:

1、空间复杂度O(1),最好时间复杂度O(n),最坏时间复杂度O(n^2),平均时间复杂度O(n^2)。

2、冒泡排序时稳定的。

快速排序

基本思想:

通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列

递归版

	public static int partition(int[] arr,int start,int end){
	    int part=arr[start];
	    int locate=start;
	    while(start<end){
	        while(end>start&&arr[end]>part)end--;
	        if(end<=start){
	            break;
	        }
	        arr[locate]=arr[end];
	        locate=end;
	        while(start<end&&arr[start]<=part) start++;
	        if(start>=end){
	            break;
	        }
	        arr[locate]=arr[start];
	        locate=start;
	    }
	    arr[locate]=part;
	    return locate;
	}
	public static void quickSort(int[] arr,int start,int end){
	    if(start>=end) return;
	    int mid=partition(arr,start,end);
	    quickSort(arr,start,mid-1);
	    quickSort(arr,mid+1,end);
	}

跌代版

    public static void quickSort(int[] arr){
	    Stack<Integer> stack=new Stack<Integer>();
	    stack.push(0);stack.push(arr.length-1);
	    while(stack.empty()==false){
	        int end=stack.pop(),start=stack.pop();
	        if(start>=end) continue;
	        int part=arr[start];
	        int locate =start;
	        int pre=start,post=end;
	        while(pre<post){
	            while(pre<post&&arr[post]>part)post--;
	            if(pre>post) break;
	            arr[locate]=arr[post];
	            locate=post;
	            while(pre<post&&arr[pre]<=part)pre++;
	            if(pre>post) break;
	            arr[locate]=arr[pre];
	            locate=pre;
	        }
	        arr[locate]=part;
	        stack.push(start);stack.push(locate-1);
	        stack.push(locate+1);stack.push(end);
	    }
	}

特征分析:

1、最好空间复杂度O(log(n)),最坏空间复杂度O(n),平均空间复杂度O(log
n);最好时间复杂度O(n log n),最坏时间复杂度O(n^2),平均时间复杂度O(n log n)。

2、快速排序时不稳定的。

改进

在最坏的情况下,每次划分都将n个元素划分为n-1个元素和1个元素,我们可以通过采取措施尽量较少这种不对称划分来优化算法。例如,我们在选取划分元素时,不是选取特定位置的元素,而是采取随机选取的方式或者随机取三个元素并选定其中值进行划分。

归并排序

基本思想:

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide
and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并

递归版

	public static void merge(int[] arr,int start1,int start2,int end2,int[] temp){
	    int end1=start2-1,index=0;
	    int p=start1,q=start2;
	    while(p<=end1||q<=end2){
	        if(q>end2||(p<=end1&&arr[p]<arr[q])){
	            temp[index++]=arr[p++];
	        }else{
	            temp[index++]=arr[q++];
	        }
	    }
	    for(int i=0;i<index;i++){
	        arr[start1+i]=temp[i];
	    }
	}
    public static void mergeSort(int[] arr,int start,int end,int[] temp){
        if(start>=end) return;
        int mid=start+(end-start)/2;
        mergeSort(arr,start,mid,temp);
        mergeSort(arr,mid+1,end,temp);
        merge(arr,start,mid+1,end,temp);
    } 

迭代版

public static void mergeSort(int[] arr,int[] temp){
        int size=1,low,mid,high,n=arr.length;
        while(size<=n-1)
        {
            low=0;
            while(low+size<=n-1)
            {
                mid=low+size-1;
                high=mid+size;
                if(high>n-1)//第二个序列个数不足size
                    high=n-1;
                merge(arr,low,mid+1,high,temp);//调用归并子函数
                System.out.println("low:"+low+" mid:"+mid+" high:"+high);
                low=high+1;//下一次归并时第一关序列的下界
            }
            size*=2;//范围扩大一倍
        }
    } 

特征分析:

1、空间复杂度O(n),时间复杂度O(1)。

2、归并排序时稳定的排序。

线性时间排序

计数排序

基本思想:

是对于给定的输入序列中的每一个元素x,确定该序列中值小于x的元素的个数(此处并非比较各元素的大小,而是通过对元素值的计数和计数值的累加来确定)。一旦有了这个信息,就可以将x直接存放到最终的输出序列的正确位置上。例如,如果输入序列中只有17个元素的值小于x的值,则x可以直接存放在输出序列的第18个位置上。当然,如果有多个元素具有相同的值时,我们不能将这些元素放在输出序列的同一个位置上,因此,上述方案还要作适当的修改。

public static int[] countSort(int[] a){
	int b[] = new int[a.length];
        int max = a[0],min = a[0];
        for(int i:a){
            if(i>max) max=i;
            if(i<min) min=i;
        }//这里k的大小是要排序的数组中,元素大小的极值差+1
        int k=max-min+1;
        int c[]=new int[k];
        for(int i=0;i<a.length;++i){
            c[a[i]-min]+=1;//优化过的地方,减小了数组c的大小
        }
        for(int i=1;i<c.length;++i){
            c[i]=c[i]+c[i-1];
        }
        for(int i=a.length-1;i>=0;--i){
            b[--c[a[i]-min]]=a[i];//按存取的方式取出c的元素
        }
        return b;
}

特征分析:

1、空间复杂度O(k+n)(k为数据范围),时间复杂度O(n+k)。

2、计数排序时稳定的。

变形:

出来了通过统计出现次数之外,我们还可以用链表记录数值相同的元素。

适用场景:

1、当k=O(n)时。

基数排序

基本思想:

基数排序(radix
sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用。

    // d为数据长度
    private static void radixSorting(int[] arr, int d) {
        for (int i = 1; i <=d; i++) {
            int[] res = countingSort(arr, i); // 依次对各位数字排序(直接用计数排序的变体)
            for(int j=0;j<arr.length;j++){
                arr[j]=res[j];
            }
        }
    }
    // 利用计数排序对元素的每一位进行排序
    private static int[] countingSort(int[] arr, int expIndex) {
        int k = 9;
        int[] b = new int[arr.length];
        int[] c = new int[k + 1]; // 这里比较特殊:数的每一位最大数为9
        for (int i = 0; i < k; i++) {
            c[i] = 0;
        }
        for (int i = 0; i < arr.length; i++) {
            int d = getBitData(arr[i], expIndex);
            c[d]++;
        }
        for (int i = 1; i <= k; i++) {
            c[i] += c[i - 1];
        }
        for (int i = arr.length - 1; i >= 0; i--) {
            int d = getBitData(arr[i], expIndex);
            b[c[d] - 1] = arr[i];// C[d]-1 就代表小于等于元素d的元素个数,就是d在B的位置
            c[d]--;
        }
        return b;
    }
    // 获取data指定位的数
    private static int getBitData(int data, int expIndex) {
        while (data != 0 && expIndex > 0) {
            data /= 10;
            expIndex--;
        }
        return data % 10;
    }

	public static int[] countSort(int[] a){
	    int b[] = new int[a.length];
        int max = a[0],min = a[0];
        for(int i:a){
            if(i>max) max=i;
            if(i<min) min=i;
        }//这里k的大小是要排序的数组中,元素大小的极值差+1
        int k=max-min+1;
        int c[]=new int[k];
        for(int i=0;i<a.length;++i){
            c[a[i]-min]+=1;//优化过的地方,减小了数组c的大小
        }
        for(int i=1;i<c.length;++i){
            c[i]=c[i]+c[i-1];
        }
        for(int i=a.length-1;i>=0;--i){
            b[--c[a[i]-min]]=a[i];//按存取的方式取出c的元素
        }
        return b;
	}

特征分析:

1、基数排序法是属于稳定性的排序。

2、时间复杂度为O
(nlog(k)d),其中d为所采取的基数,而k为堆数,在某些时候,基数排序法的效率高于其它的稳定性排序法。

桶排序

基本思想:

将数组分到有限数量的桶子里。每个桶子再个别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序)。桶排序利用函数的映射关系,减少了几乎所有的比较工作。实际上,桶排序的f(k)值的计算,其作用就相当于快排中划分,已经把大量数据分割成了基本有序的数据块(桶)。然后只需要对桶中的少量数据做先进的比较排序即可。

简单桶排序实现

	//假如排序的数据范围为(0-100),学生成绩
    public static void bucketSort(int[] arr){
        List<List<Integer>> buckets=new ArrayList<List<Integer>>();
        buckets.add(new ArrayList<Integer>());//成绩0-59的桶
        buckets.add(new ArrayList<Integer>());//成绩60-69
        buckets.add(new ArrayList<Integer>());//成绩70-79
        buckets.add(new ArrayList<Integer>());//成绩80-100
        for(int i:arr){
            if(i>=0&&i<=59)    buckets.get(0).add(i);
            if(i>=60&&i<=69)   buckets.get(1).add(i);
            if(i>=70&&i<=79)   buckets.get(2).add(i);
            if(i>=80&&i<=100)  buckets.get(3).add(i);
        }
        for(List<Integer> bucket:buckets){
            Collections.sort(bucket);
        }
        int index=0;
        for(List<Integer> bucket:buckets){
            for(int i:bucket){
                arr[index++]=i;
            }
        }
    }

特征分析:

1、对于N个待排数据,M个桶,如果相对于同样的N,桶数量M越大,其效率越高,最好的时间复杂度达到O(N)。当然桶排序的空间复杂度为O(N+M),如果输入数据非常庞大,而桶的数量也非常多,则空间代价无疑是昂贵的。

2、桶排序是稳定的(如果桶内数据的排序算法选择的不是稳定的,桶排序就变成不稳定的)。

适用场景:

1、输入数据符合均匀分布。

2、在面试的海量数据处理题目中,如对每天数以亿计的数据进行排序,直接排序即使采用nlgn的算法,依然是一件很恐怖的事情,内存也无法容纳如此多的数据,这时桶排序就可以有效地降低数据的数量级,再对降低了数量级的数据进行排序,可以得到比较良好的效果。

面试题

public class Solution {
    public boolean isAnagram(String s, String t) {
    	if(s.length()!=t.length()) return false;
        char[] a=s.toCharArray();
        char[] b=t.toCharArray();
        Arrays.sort(a);
        Arrays.sort(b);
        boolean res;
        for(int i=0;i<a.length;i++){
        	if(a[i]!=b[i]){
        		return false;
        	}
        }
        return true;
    }
}

分析

题目中指明不能利用类库中的排序函数,即使允许效率也是低下的。

由于元素的值是确切的三种类型,0、1、2。我们可以利用快速排序的划分算法,每次划分就可以解决一个数值的元素的排序。

public class Solution {
	public int partition(int[] nums,int value,int begin,int end){
		int p=begin,q=end;
		while(p<q){
			while(p<=end&&nums[p]==value)p++;
			while(q>=begin&&nums[q]>value)q--;
			if(p<q){
				int t=nums[p];nums[p]=nums[q];nums[q]=t;
			}
		}
		return p;
	}
    public void sortColors(int[] nums) {
        if(nums.length<=1) return;
        int nextBegin=partition(nums,0,0,nums.length-1);
        if(nextBegin<nums.length){
        	partition(nums,1,nextBegin,nums.length-1);
        }
    }
}

分析

链表只具有顺序存取特性,只能使用简单插入排序。

public class Solution {
    public ListNode insertionSortList(ListNode head) {
    	ListNode myHead=new ListNode(-1),p;
    	while(head!=null){
    		p=head;
    		head=head.next;
    		insertElement(myHead,p);
    	}
    	return myHead.next;
    }
    private void insertElement(ListNode myHead,ListNode p){
    	ListNode pre=myHead,post=myHead.next;
    	while(post!=null&&post.val<=p.val){
    		pre=post;
    		post=post.next;
    	}
    	p.next=post;
    	pre.next=p;
    }
}

分析

由于要求时间复杂度为O(n log n),空间复杂度O(1)。那么我们想到符合这样的复杂度的排序算法只可能为堆排序、归并排序。

由于空间复杂度为O(1)的堆排序,要求随机存取特性,而链表显然不具有这样的特性,因此只能使用归并排序。

    public static ListNode sortList(ListNode head) {
    	int length=0;
    	ListNode p=head;
    	while(p!=null){
    		length++;
    		p=p.next;
    	}
    	if(length<=1) return head;
    	ListNode myHead=new ListNode(-1);
    	myHead.next=head;
		mergerSort(myHead,length);
        return myHead.next;
    }
    private static void mergerSort(ListNode myHead,int length){
    	ListNode pre,start,end;
    	int size=1;
    	while(size<length){
    		pre=myHead;
    		while(pre.next!=null){
    			start=pre.next;
    			pre.next=merge(start,size);
    			int count=size*2;
    			while(count>0&&pre!=null){
    				pre=pre.next;
    				count--;
    			}
    			if(count>0||pre==null||pre.next==null) break;
    		}
    		size*=2;
    	}
    }
    private static ListNode merge(ListNode start,int size){
    	ListNode myHead=new ListNode(-1),end=myHead,second,last;
    	int count=size;
    	second=start;
    	while(count>0&&second!=null){
    		second=second.next;
    		count--;
    	}
    	if(count>0) return start;//长度不够一个size
    	count=size;
    	last=second;
    	while(count>0&&last!=null){
    		last=last.next;
    		count--;
    	}
    	ListNode p=start,q=second,t;
    	while(p!=second||q!=last){
    		if(q==last||(p!=second&&p.val<=q.val)){

    			t=p;
    			p=p.next;
    			t.next=null;
    			end.next=t;
    			end=end.next;
    		}else{
    			t=q;
    			q=q.next;
    			t.next=null;
    			end.next=t;
    			end=end.next;
    		}
    	}
    	end.next=last;
		return myHead.next;
    }

public class Solution {
    public String largestNumber(int[] nums) {
        if (nums == null || nums.length == 0) return "";
        String[] strs = new String[nums.length];
        for (int i = 0; i < nums.length; i++) {
            strs[i] = nums[i]+"";
        }
        Arrays.sort(strs, new Comparator<String>() {
            @Override
            public int compare(String i, String j) {
                String s1 = i+j;
                String s2 = j+i;
                return s2.compareTo(s1);
            }
        });
        //降序,直接比较i+j和j+i,就可以判断哪个应该放在前面
        if (strs[0].charAt(0) == '0') return "0";//最大为0,结果必为0
        StringBuilder res = new StringBuilder();
        for (String s:strs) {
            res.append(s);
        }
        return res.toString();
    }
}
时间: 2024-08-03 09:04:35

排序算法总结及面试题的相关文章

前端排序算法总结;前端面试题2.0;JavaScript异步编程

1.前端 排序算法总结 排序算法可能是你学编程第一个学习的算法,还记得冒泡吗? 当然,排序和查找两类算法是面试的热门选项.如果你是一个会写快排的程序猿,面试官在比较你和一个连快排都不会写的人的时候,会优先选择你的.那么,前端需要会排序吗?答案是毋庸置疑的,必须会.现在的前端对计算机基础要求越来越高了,如果连排序这些算法都不会,那么发展前景就有限了.本篇将会总结一下,在前端的一些排序算法. https://segmentfault.com/a/11... 2.前端面试题 V2.0 详见: 这是一份

数据结构基础 排序算法(一) 概念篇

本辑将会对笔试面试最常涉及到的12种排序算法(包括插入排序.二分插入排序.希尔排序.选择排序.冒泡排序.鸡尾酒排序.快速排序.堆排序.归并排序.桶排序.计数排序和基数排序)进行详解.每一种算法都有基本介绍.算法原理分析.图解演示.算法代码.笔试面试重点分析.笔试面试题等板块. 一.插入排序 1)算法简介 插入排序(Insertion Sort)的算法描述是一种简单直观的排序算法.它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入.插入排序在实现上,通常

深入理解排序算法(一):初级排序算法

[本系列博文会对常见的排序算法进行分析与总结,并会在最后提供几道相关的一线互联网企业面试/笔试题来巩固所学及帮助我们查漏补缺.项目地址:https://github.com/absfree/Algo.由于个人水平有限,叙述中难免存在不清晰准确的地方,希望大家可以指正,谢谢大家:)] 一.概述 我们在日常开发中经常需要对一组数据对象进行排序,这里的数据对象不仅包括数字,还可能是字符串等抽象数据类型(Abstract Data Type).由于排序是很多其他操作(比如二分查找)能够高效进行的基础,因

高校挑战赛:观看世界杯--限制排序算法

试题来源:http://student.csdn.net/mcs/programming_challenges?&page=1  观看世界杯 以前在学校参加每年的ACM程序设计大赛,感觉程序算法还是挺有意思的,这两天发现一个网站上放出一些算法试题,有点当年的那种心情,看到了,感觉能干掉,那就干掉它.目前还在公司守夜中,闲着没事就试了试算法题. 速手打,没有详细检查,可能有瑕疵请见谅,但是读题.解题.算法设计,一个不少. if(type == 1){...} 这段里,虽然写的有点小复杂,但是是个简

12种排序算法:原理、图解、动画视频演示、代码以及笔试面试题目中的应用

出处:http://blog.csdn.net/han_xiaoyang/article/details/12163251. 声明:版权所有,转载请注明出处,谢谢. 0.前言 从这一部分开始直接切入我们计算机互联网笔试面试中的重头戏算法了,初始的想法是找一条主线,比如数据结构或者解题思路方法,将博主见过做过整理过的算法题逐个分析一遍(博主当年自己学算法就是用这种比较笨的刷题学的,囧),不过又想了想,算法这东西,博主自己学的过程中一直深感,基础还是非常重要的,很多难题是基础类数据结构和题目的思想综

几种排序算法的C++实现——快速排序、堆排序、基数排序

排序算法是非常常见的面试笔试问题,考查的一个人的基本功,本文将一些排序做了C++的实现,就当是做个学习总结吧. 1.快速排序 快速排序的中心是填坑法,取一个数(这里选取第一个数)作为基准数temp,从队尾开始寻找第一个比基准数小的数a[j],交换a[j]和temp,然后队首开始查找第一个比temp大的数a[i],交换之,遍历的结果是当i>=j时,temp左边的数都小于temp,后边的数都大于temp,这个有点像归并排序.最后利用递归调用完成排序,代码如下: 1 void QuickSort(in

Java笔记(07):常见对象--StringBuffer、二分查找及排序算法

1.StringBuffer类的构造方法 1 package cn.itcast_01; 2 3 /* 4 * 线程安全(多线程讲解) 5 * 安全 -- 同步 -- 数据是安全的 6 * 不安全 -- 不同步 -- 效率高一些 7 * 安全和效率问题是永远困扰我们的问题. 8 * 安全:医院的网站,银行网站 9 * 效率:新闻网站,论坛之类的 10 * 11 * StringBuffer: 12 * 线程安全的可变字符串. 13 * 14 * StringBuffer和String的区别? 1

常用排序算法的python实现和性能分析

http://www.cnblogs.com/wiki-royzhang/p/3614694.html 一年一度的换工作高峰又到了,HR大概每天都塞几份简历过来,基本上一天安排两个面试的话,当天就只能加班干活了.趁着面试别人的机会,自己也把一些基础算法和一些面试题整了一下,可以阶段性的留下些脚印——没办法,平时太忙,基本上没有时间写博客.面试测试开发的话,这些也许能帮得上一些. 这篇是关于排序的,把常见的排序算法和面试中经常提到的一些问题整理了一下.这里面大概有3个需要提到的问题: 虽然专业是数

面试常考各类排序算法总结.(c#)

一. 面试以及考试过程中必会出现一道排序算法面试题,为了加深对排序算法的理解,在此我对各种排序算法做个总结归纳. 1.冒泡排序算法(BubbleSort) 1 public Class SortDemo 2 { 3 public void BubbleSort(int arr) 4 { 5 int temp=0; 6 //需要走arr.Length-1 趟 7 for(int i=0;i<arr.Length-1;i++) 8 { 9 //每一趟需要比较次数 10 for(int j=0,j<