排序、查找算法齐全(程序员必会 好文 值得收藏!)

1、 绪论

  • 身为程序员,十大排序是对每一个程序员都应该掌握的算法,现在比较流行的算法如快速排序、归并排序等,对算法的时间复杂度和空间复杂度的掌握都有要求。本文将分享常见的十大排序算法,基于Java和C语言实现,让你能够掌握!

排序算法是《数据机构与算法》中最基本的算法之一。
排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序的,而外部排序是因为排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。常见的内部排序算法有:插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序、基数排序等。

  • 对于排序的分类,可以根据不同的角度比如时间、空间复杂度、比较、非比较等角度来划分。我们通常的十大排序都是内部排序,通常的话,基于[比较和非比较]这个层次来划分:

如图:
在这里插入图片描述

2、交换类

2-1冒泡排序

基本思想:循环遍历多次,每次从前往后把大元素往后调,每次确定一个最大(最小)元素,多次到达排序序列。

2-1-1动画演示

在这里插入图片描述

  • Java实现代码:
	/*
	 * 1、冒泡排序
	 */
	public static void maoPaoSort(int[] array) { 
		for(int i=array.length-1;i>=0;i--) {
			for(int j=0;j<i;j++) {
				if(array[j]>=array[j+1]) {
					int t=array[j];
					array[j]=array[j+1];
					array[j+1]=t;
				}
			}
		}
	}
  • C语言实现代码:
void bubble_sort(int a[], int n)     
{
    int i,j,temp;     
    for (j=0;j<n-1;j++)      
    {                           
        for (i=0;i<n-1-j;i++)
        {
            if(a[i]>a[i+1])  
            {
                temp=a[i];      
                a[i]=a[i+1];    
                a[i+1]=temp;
            }
        }
    }    
}

2-2快速排序

基本思想:将一个序列分为2部分,序列左边全部小于一个数,序列右边全部大于一个数。然后利用递归的思想再将左序列当成一个完整的序列再进行排序,同样把序列的右侧也当成一个完整的序列进行排序。

2-2-1动画演示

在这里插入图片描述

  • Java实现代码:
	/*
	 * 2、快速排序
	 */
	public static void quickSort(int[] array,int left,int right) {
		int low=left;
		int high=right;
		if(low>high) {
			return ;
		}
		int k=array[low];
		while(low<high) {
			while(low<high&&array[high]>=k) {
				high--;
			}
			array[low]=array[high];
			while(low<high&&array[low]<=k) {
				low++;
			}
			array[high]=array[low];
		}
		array[low]=k;
		quickSort(array,left,low-1);
		quickSort(array,low+1,right);
	}
  • C语言实现代码:
void QuickSort(int* data, int left, int right, int direction)
{
	int i = left, j = right, index = data[left];
	if (data == NULL)
		return;
	if (right >= sizeof(*data)/sizeof(int))return;
	if (left < 0)
		return;

	if (left >= right)
		return;
	while(i<j)
	{
		while(data[j]<=index)
			j--;
		data[i] = data[j];
		while(data[i]>=index&&i < j)
			i++;
		data[j]=data[i];
	}
	data[i]=index;
	QuickSort(data,left,i-1,direction);
	QuickSort(data,i+1,right,direction);
}

3、插入类

3-1直接插入排序

基本思想:简单的说,就是按身高来排序,从第一个开始,如果前面有比自己高的,就直接插入到合适的位置。一直到队伍的最后一个完成插入,整个队列才能满足有序。

3-1-1动画演示

在这里插入图片描述

  • Java实现代码:
	/*
	 * 3、直接插入排序
	 */
	public static void insertSort(int[] array) {
		int temp=0;
		for(int i=1;i<array.length;i++) {
			temp=array[i];
			for(int j=i-1;j>=0;j--) {
				if(array[j]>temp) {
					array[j+1]=array[j];
					array[j]=temp;
				}else {
					break;
				}
			}
		}
	}
  • C语言实现代码:
void insertsort(int *k,int n)            
{
    int i,j;
    int temp;
    for(i=1;i<n;i++)
    {
        temp = k[i];               
        j = i - 1;
        while(j>=0 && k[j]>temp)    
        {
            k[j+1] = k[j];           
            j--;
        }
        k[j+1] = temp;                 
    }
}

3-2希尔排序

基本思想:希尔排序是特殊的插入排序,直接插入排序每次插入前的遍历步长为1,而希尔排序是将待排序列分为若干个子序列,对这些子序列分别进行直接插入排序,当每个子序列长度为1时,再进行一次直接插入排序时,结果一定是有序的。常见的划分子序列的方法有:初始步长(两个子序列相应元素相差的距离)为要排的数的一半,之后每执行一次步长折半。

3-2-1动画演示

在这里插入图片描述

  • Java实现代码:
/*
	 * 4、希尔排序
	 */
	public static void shellSort(int[] array) {
		int len=array.length;
		int temp=0;
		for(;len>=1;len/=2) {
			for(int i=len;i<array.length;i++) {
				temp=array[i];
				for(int j=i-len;j>=0;j-=len) {
					if(array[j]>temp) {
						array[j+len]=array[j];
						array[j]=temp;
					}else {
						break;
					}
				}
			}
		}
	}
  • C语言实现代码:
void shellSort(int *a, int len)
{
    int i, j, k, tmp, gap;  
    for(gap=len/2;gap>0;gap/=2) {  
    	for(i=0;i<gap;++i) { 
	        for(j=i+gap;j<len;j+=gap) { 
	            tmp=a[j];  
	            k=j-gap;  
	            while(k>=0&&a[k]>tmp) {
	                a[k+gap]=a[k]; 
	                k-=gap;
	            }
	            a[k+gap]=tmp; 
	        }
	    }
    }
}

4、选择类

4-1简单选择排序

基本思想:首先,选出最小的数,放在第一个位置;然后,选出第二小的数,放在第二个位置;以此类推,直到所有的数从小到大排序。

4-1-1动画演示

在这里插入图片描述

  • Java实现代码:
	/*
	 *5、 简单选择排序
	 */
	public static void selectSort(int[] array) {
		for(int i=0;i<array.length-1;i++) {
			int min=i;
			for(int j=i+1;j<array.length;j++) {
				if(array[j]<array[min]) {
					min=j;
				}
			}
			if(min!=i) {
				swap1(array,i,min);
			}
		}
	}
	public static void swap1(int[] array,int i,int j) {
		int t=array[i];
		array[i]=array[j];
		array[j]=t;
	}
  • C语言实现代码:
void SelectSort(int a[],int n){ 
    int mix,temp;
    int i,j;
    for(i=0;i<n-1;i++){ 
        mix=i; 
        for(j=i+1;j<n;j++)
            if(a[j]<a[mix])
                mix=j;
        if(i!=mix) {
            temp=a[i];
            a[i]=a[mix];
            a[mix]=temp;
        }
    }
}

4-2堆排序

基本思想:将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了。

4-2-1动画演示

在这里插入图片描述

  • Java实现代码:
	/*
	 * 6、堆排序
	 */
	public static void swap2(int[] array,int m,int n) {
		int t=array[m];
		array[m]=array[n];
		array[n]=t;
	}
	public static void shiftDown(int[] array,int index,int len) {
		int left=index*2+1;
		int right=index*2+2;
		if(left>=len) {
			return ;
		}else if(right<len&&array[right]<array[index]&&array[right]<array[left]) {
			swap2(array, index, right);
		    shiftDown(array, right, len);
		}else if(array[left]<array[index]) {
			swap2(array, index, left);
		    shiftDown(array, left, len);
		}
	}
	public static void createHeap(int[] array) {
		for(int i=array.length/2;i>=0;i--) {
			shiftDown(array, i,array.length);
		}
	}
	public static void heapSort(int[] array) {
		int[] val=new int[array.length];
		createHeap(array);
		for(int i=0;i<array.length;i++) {
			val[i]=array[0];
		    array[0]=array[array.length-1-i];
		    shiftDown(array, 0, array.length-i);
		}
		for(int i=0;i<array.length;i++) {
			array[i]=val[i];
		}
	}
  • C语言实现代码:
void AdjustDown(DataType* a, size_t n, int parent)
{
    int child = parent * 2 + 1;
    while(child < n)
    {
        if((child + 1 < n)&&(a[child+1]>a[child]))
        {
            ++child;
        }
        if(a[child]>a[parent])
        {
            Swap(&a[child], &a[parent]);
            parent=child;
            child = parent * 2 + 1;
        }
        else
        {
            break;
        }
    }
}
void HeapSort(DataType* a, size_t n)
{
    assert(a);
    for(int i = (n - 2) / 2; i >= 0; i--)
    {                       
        AdjustDown(a, n, i);
    }
    int end = n - 1;
    while(end > 0)
    {
        Swap(&a[0], &a[end]);
        AdjustDown(a, end, 0);
        --end;
    }
}

5、归并类

5-1归并排序

基本思想:将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并, 使用中牺牲空间换取时间的算法。

5-1-1动画演示

在这里插入图片描述

  • Java实现代码:
	/*
	 * 7、归并排序
	 */
	public static void mergeSort(int[] array,int left,int right) {
		int mid=(left+right)/2;
		  if(left<right)
		  {
			  mergeSort(array, left, mid);
			  mergeSort(array, mid+1, right);
			  merge(array, left,mid, right);
		  }
	}
	public static void merge(int[] array,int l,int mid,int r) {
		  int lindex=l;
		  int rindex=mid+1;
		  int temp[]=new int[r-l+1];
		  int teamindex=0;
		  while (lindex<=mid&&rindex<=r) {
		    if(array[lindex]<=array[rindex])
		    {
		    	temp[teamindex++]=array[lindex++];
		    }else {    
		    	temp[teamindex++]=array[rindex++];
		    }
		  }
		  while(lindex<=mid)
		  {
			  temp[teamindex++]=array[lindex++];
		  }
		  while(rindex<=r)
		  {
			  temp[teamindex++]=array[rindex++];
		  } 
		  for(int i=0;i<teamindex;i++)
		  {
			  array[l+i]=temp[i];
		  }
	}
  • C语言实现代码:
void merge(int arr[], int start, int mid, int end) {
	int result[ArrLen];
	int k = 0;
	int i = start;
	int j = mid + 1;
	while (i <= mid && j <= end) {
		if (arr[i] < arr[j]){
			result[k++] = arr[i++];
        }
		else{
			result[k++] = arr[j++];
        }
	}
	if (i == mid + 1) {
		while(j <= end)
			result[k++] = arr[j++];
	}
	if (j == end + 1) {
		while (i <= mid)
			result[k++] = arr[i++];
	}
	for (j = 0, i = start ; j < k; i++, j++) {
		arr[i] = result[j];
	}
}
void mergeSort(int arr[], int start, int end) {
	if (start >= end)
		return;
	int mid = ( start + end ) / 2;
	mergeSort(arr, start, mid);
	mergeSort(arr, mid + 1, end);
	merge(arr, start, mid, end);
}

6、桶类排序

6-1桶排序

基本思想:把数组中的所有元素分为若干个数据块,也就是若干个桶,然后对每个桶里的数据进行排序,最后将所有桶里的数据依次排列即可。

6-1-1动画演示

在这里插入图片描述

  • Java实现代码:
	/*
	 * 8、桶排序
	 */
	public static int[] bucketSort(int[] nums, int maxNum){
	    int[] sorted = new int[maxNum+1];
	    for(int i=0; i<nums.length; i++){
	        sorted[nums[i]] = nums[i];  //把数据放到对应索引的位置
	    }
	    return sorted;
	}
  • C语言实现代码:
typedef struct node {
	int key;
	struct node *next;
}KeyNode;
void bucket_sort(int keys[],int size,int bucket_size) {
	int i,j;
	KeyNode **bucket_table = (KeyNode **)malloc(bucket_size * sizeof(KeyNode*));
	for(i = 0;i < bucket_size;i++) {
		bucket_table[i] = (KeyNode*)malloc(sizeof(KeyNode));
		bucket_table[i]->key = 0;
		bucket_table[i]->next = NULL;
	}
	for(j = 0;j < size;j++) {
		KeyNode *node = (KeyNode *)malloc(sizeof(KeyNode));
		node->key = keys[j];
		node->next = NULL;
		int index = keys[j]/10;
		KeyNode *p = bucket_table[index];
		if(p->key == 0) {
			bucket_table[index]->next = node;
			(bucket_table[index]->key)++;
		}else {
			while(p->next != NULL && p->next->key <= node->key)
				p = p->next;
			node->next = p->next;
			p->next = node;
			(bucket_table[index]->key)++;
		}
	}
	KeyNode * k = NULL;
	for(i = 0;i < bucket_size;i++)
		for(k = bucket_table[i]->next;k!=NULL;k=k->next)
			printf("%d ",k->key);
	printf("\n");
}

6-2计数排序

基本思想:先找到最小值min,再找最大值max。然后创建这个区间大小的数组,从min的位置开始计数,这样就可以最大程度地压缩空间,提高空间的使用效率。

6-2-1动画演示

在这里插入图片描述

  • Java实现代码:
	/*
	 * 9、计数排序
	 */
	public static void countSort(int[] array) {
		int min=Integer.MAX_VALUE;
		int max=Integer.MIN_VALUE;
		for(int i=0;i<array.length;i++)
		{
			if(array[i]<min) 
				min=array[i];
			if(array[i]>max)
				max=array[i];
		}
		int count[]=new int[max-min+1];
		for(int i=0;i<array.length;i++)
		{
			count[array[i]-min]++;
		}
		int index=0;
		for(int i=0;i<count.length;i++)
		{
			while (count[i]-->0) {
				array[index++]=i+min;
			}
		}
	}

6-3基数排序

基本思想:将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。在每一次排序中,按照当前位把数组元素放到对应的桶当中,然后把桶0到桶9中的元素按先进先出的方式放回数组中。这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。

6-3-1动画演示

在这里插入图片描述

  • Java实现代码:
/*
	 * 10、基数排序
	 */
	public static void radixSort(int[] array) {
		List<Integer> bucket[]=new ArrayList[10];
		for(int i=0;i<10;i++)
		{
			bucket[i]=new ArrayList<Integer>();
		}
		int max=0;
		for(int i=0;i<array.length;i++)
		{
			if(array[i]>max)
				max=array[i];
		}
		int divideNum=1;
		while (max>0) {
			for(int num:array)
			{
				bucket[(num/divideNum)%10].add(num);
			}
			divideNum*=10;
			max/=10;
			int idx=0;
			for(List<Integer>list:bucket)
			{
				for(int num:list)
				{
					array[idx++]=num;
				}
				list.clear();
			}
		}
	}

7、测试

		System.out.println("测试十大排序");
		int arr[]= {30,20,10,50,90,100,80,70,89,110};
		System.out.println("排序方式一:冒泡排序");
		maoPaoSort(arr);
		System.out.println(Arrays.toString(arr));
		System.out.println("排序方式二:快速排序");
		quickSort(arr,0,arr.length-1);
		System.out.println(Arrays.toString(arr));
		System.out.println("排序方式三:插入排序");
		insertSort(arr);
		System.out.println(Arrays.toString(arr));
		System.out.println("排序方式四:希尔排序");
		shellSort(arr);
		System.out.println(Arrays.toString(arr));
		System.out.println("排序方式五:选择排序");
		selectSort(arr);
		System.out.println(Arrays.toString(arr));
		System.out.println("排序方式六:堆排序");
		heapSort(arr);
		System.out.println(Arrays.toString(arr));
		System.out.println("排序方式七:归并排序");
		mergeSort(arr,0,arr.length-1);
		System.out.println(Arrays.toString(arr));
		System.out.println("排序方式八:桶排序");
		int[] sorted=bucketSort(arr,110);
		System.out.print("[");
		for (int i = 0; i < sorted.length; i++)
	    {
	        if (sorted[i] > 0)
	            System.out.print(sorted[i]+" ");
	    }
		System.out.print("]");
		System.out.println();
		System.out.println("排序方式九:计数排序");
		countSort(arr);
		System.out.println(Arrays.toString(arr));
		System.out.println("排序方式十:基数排序");
		radixSort(arr);
		System.out.println(Arrays.toString(arr));

输出结果:
在这里插入图片描述

  • 注意:只有桶排序的测试方法稍有不同,其他排序方法基本一致。

8、六大查找算法

  • 查找是在大量的信息中寻找一个特定的信息元素,在计算机应用中,查找是常用的基本运算,例如编译程序中符号标的查找。
  • 查找算法分类:
    1)静态查找和动态查找:
    注意:静态或者动态都是针对查找表而言的。动态表指查找表中有删除和插入操作的表。
    2)无序查找和有序查找:
    无序查找:被查找数列有序无序均可。
    有序查找:被查找数列必须为有序数列。

8-1 顺序查找

顺序查找

  • 算法简介: 顺序查找又称为线性查找,是一种最简单的查找算法。适用于线性表的顺序存储结构和链式存储结构。该算法的时间复杂度为O(n)。
  • 基本思路: 从第一个元素m开始逐个与需要查找的元素x进行比较,当比较到元素值相同(m==x)时返回元素m的下标,如果比较到最后都没有找到,则返回-1。
  • 算法分析: 时间复杂度为O(n)。

8-2 二分法查找

二分法查找

  • 算法简介: 二分法查找(Binary Search),是一种在有序数组中查找某一特定的元素的查找算法。查找过程从数组的中间的元素开始,如果中间元素正好是要查找的元素,则查找过程结束;如果元素大于或者小于中间元素,则在数组大于或者小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。
  • 算法分析: 时间复杂度【折半查找每次把搜索区域减少一半,时间复杂度为O(logn)】。空间复杂度【O(1)】。

8-3 插值查找

插值查找

  • 算法简介: 插值查找是根据要查找的关键字key与查找表中最大最小记录的关键字比较后的查找方法,其核心在于插值的计算公式。基于二分法查找算法,将查找的选择改进为自适应选择,可以提高查找效率。当然,插值查找也属于有序查找

注意:对于表长较大,而关键字分布又比较均匀的查找表来说,插值算法的查找性能要比折半查找要好一些。反之,数组中如果分布非常不均匀,那么插值查找未必是和合适的选择。

  • 算法分析: 时间复杂度【如果元素分布均匀,则为O(loglogn)),在最坏情况下为O(n)】。空间复杂度【O(1)】。

8-4 斐波拉契查找

斐波拉契查找

  • 算法简介: 斐波拉契数列,又称为黄金分割数列。斐波拉契查找就是在二分法的基础上进行分割的。在斐波拉契数列找一个等于稍大于查找表中元素个数的F[n],将原查找表扩展为长度为F[n](如果要补充元素,则补充重复最后一个元素,知道满足F[n]个元素),完成后进行斐波拉契分割,即F[n]个元素分割为前半部分F[n-1]个元素,后半部分F[n-2]个元素,找出要查找的元素在那一部分并递归,直到找到。
  • 算法分析: 最坏情况下,时间复杂度为O(log2n)。

8-5 分块查找

分块查找

  • 算法简介: 要求查找的是顺序表,分块查找又称为索引顺序查找,它是顺序查找的一种改进方法。将n个数据元素“按块有序”划分为m块(m<=n);每一块中的节点不必有序,但块与块之间必须“按块有序”;即第一块中任意元素都必须小于第二块中任意元素的关键字,以此类推…
  • 算法分析: 时间复杂度为O(log(m)+N/m)。

8-6 哈希查找

哈希查找

  • 算法简介: 哈希表就是一种以键-值存储的数据结构,只要输入待查找的值key,即可查找到对应的值。哈希的思路简单,如果所有的键都是整数,那么就可以使用一个简单无序数组来实现:将键作为索引,值即为其对应的值,这样就可以快速的访问任意键的值。这是对于简单的键的情况,我们将其扩展到可以处理更加复杂的类型的键。
  • 算法分析: 复杂度为O(1)。

9、必备

十大排序、六大查找算法就分享大家了,喜欢的话就收藏吧。
在这里插入图片描述

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值