排序算法大全

二分查找方式的排序

  1. 有数数组
  2. 平衡二叉树:时间复杂度O(log2n)
    AVL
    红黑树
  3. 平衡多路搜索树
    B树
    B+树
  4. 多层有序列表
    跳表结构

排序算法简介

十一种排序
下图是传统的十一种排序的对比情况。十一种排序的详细信息

暴力做法

	冒泡:
		不断比较相邻两个数据将其排序放置,
	选择:
		找到最小/最大的数据将其放到前面。
	插入
			元素越少,排序效率越高
			数组越接近有序,排序效率越高

希尔排序

时间复杂度:O(n^1.5)
利用插入排序的特性,分组进行插入排序
不停的分组,让插入排序越发的快捷,从而达到了优化插入排序的目的

在这里插入图片描述

//从前往后插入排序
int shell_sort_font(int *data, int length)
{
	int gap = 0;
	int i = 0, j = 0;
	int temp;
	//分组
	for (gap=length/2; gap>=1; gap/=2)
	{
		//计算到每个组
		for(i=0; i<gap; i++)
		{
			//每组插入排序
			temp = data[i];
			for(j=i+gap; j<length && data[j] <= temp; j+=gap)
			{
				data[j-gap] = data[j];
			}
			data[j-gap] = temp;
		}
	}
}
//从后往前插入排序
int shell_sort(int *data, int length) {
    int gap = 0; //分组的跨度
    int i = 0, j = 0;
    for (gap = length / 2; gap >= 1;gap /= 2) { // 分组的次数
        for(i = gap; i < length; i ++) { // 每组遍历 
            int temp = data[i];
            for (j = i - gap; j >= 0 && temp < data[j];j = j - gap) { //组内排序
                data[j+gap] = data[j];
            }
            data[j+gap] = temp;
        }
    }
    return 0;
}

归并排序

采用分治理念,进行递归排序。
在这里插入图片描述


void merge(int a[],int l,int r,int mid)
{
  int aux[r-l+1],i,j,k;
  
  for(k=l;k<=r;k++)
  aux[k-l]=a[k];
  
  i=l;
  j=mid+1;
  for(k=l;k<=r;k++)
  {
  	if(i>mid)
  	{
  		a[k]=aux[j-l];
  		j++;
	  }
		else if(j>r)
		{
			a[k]=aux[i-l];
			i++;
	  }
		else if(aux[i-l]>aux[j-l])
		{
			a[k]=aux[j-l];
			j++;
		}
		else
		{
			a[k]=aux[i-l];
			i++;
		}
	}	
}
void merge_sort(int a[],int l,int r)
{
    if(l>=r)
	return ;
	
	int mid=(l+r)/2;
	
	merge_sort(a,l,mid);
	merge_sort(a,mid+1,r);
	merge(a,l,r,mid);
	
}


 void merge_sort2(int a[], int len)
 {
	 int i,j,k;
	 int step;
	 for(i=1;i<=len/2;i<<=1)
	 {
		 k=0;
		 step = i*2;
		 for(j=0;j<len-step; j+=step)
		 {
			 merge(a,j,j+step-1,(j+j+step-1)/2);
		 }
		 if(j<len)
		 {
			 merge(a,j,len-1,(j+len-1)/2);
		 }		
	 }
 }

快速排序

寻找一个基准值,将比他大的数据跟比他小的数据放到它的两边

int quick_sort(int *data, int length)
{
        int *temp = 0;
        int standard = data[0];
        int i,j,k;
        if(length <= 1)
        {
                return 0;
        }

        temp = calloc(length, sizeof(int));
        for(i=1,j=0,k=length-1; i<length; i++)
        {
                if(standard < data[i])
                {
                        temp[k--] = data[i];
                }
                else
                {
                        temp[j++] = data[i];
                }
        }
        temp[j] = standard;
        memcpy(data, temp, length*sizeof(int));

        free(temp);
        quick_sort(data,j);
        quick_sort(data+j+1,length-j-1);
}

堆排序

暂不理解,贴上代码,后续补齐相关知识点

void swap(int *a, int *b) {
    int temp = *b;
    *b = *a;
    *a = temp;
}

void max_heapify(int arr[], int start, int end) {
    // 建立父節點指標和子節點指標
    int dad = start;
    int son = dad * 2 + 1;
    while (son <= end) { // 若子節點指標在範圍內才做比較
        if (son + 1 <= end && arr[son] < arr[son + 1]) // 先比較兩個子節點大小,選擇最大的
            son++;
        if (arr[dad] > arr[son]) //如果父節點大於子節點代表調整完畢,直接跳出函數
            return;
        else { // 否則交換父子內容再繼續子節點和孫節點比較
            swap(&arr[dad], &arr[son]);
            dad = son;
            son = dad * 2 + 1;
        }
    }
}

void heap_sort(int arr[], int len) {
    int i;
    // 初始化,i從最後一個父節點開始調整
    for (i = len / 2 - 1; i >= 0; i--)
        max_heapify(arr, i, len - 1);
    // 先將第一個元素和已排好元素前一位做交換,再重新調整,直到排序完畢
    for (i = len - 1; i > 0; i--) {
        swap(&arr[0], &arr[i]);
        max_heapify(arr, 0, i - 1);
    }
}

计数排序

以空间换时间的算法,使用该算法的前提条件比较苛刻

  1. 所有元素是整数
  2. 元素个数是有限个数

算法逻辑:

  1. 将所有元素当作一个数组的下标,用以统计每个下标处数据的个数
  2. 按照数组顺序以及统计个数输出结果
int countSort3(int *A, int len, int *result) {
    // 找出数组A中的最大值、最小值
    int min = A[0];
    int min = A[0];
    int i;
    int *count;
    for (i=1; i<len; i++) {
    	if(min > A[i])
    		min = A[i];
    	if(max < A[i])
    		max = A[i];
    }
    // 初始化计数数组count
    // 长度为最大值减最小值加1
    count = calloc(max-min+1, sizeof(int));
    // 对计数数组各元素赋值
    for (i=0;i<len;i++) {
        // A中的元素要减去最小值,再作为新索引
        count[A[i]-min]++;
    }
    // 计数数组变形,新元素的值是前面元素累加之和的值
    for (int i=1; i<=max-min; i++) {
        count[i] += count[i-1];
    }
    
    // 遍历A中的元素,填充到结果数组中去
    for (int j=0; j<len; j++) {
        result[count[A[j]-min]-1] = A[j];
        count[A[j]-min]--;
    }
    free(count);
}

桶排序

将待排序数组按照大小进行分组,比如1000个数(1000以内),将其分到10个桶(数组)里面进行排序, 可以采用[0,99],[100,199],[200,299],[300,399],[400,499],[500,599],[600,699],[700,799],[800,899],[900,999]
再对每个区间内数据进行排序。 最后再合并到一起。

//关于分桶这一块暂时想不到如何最好的方式分出合适数量的桶,可以先参考https://blog.csdn.net/developer1024/article/details/79770240

基数排序

也是桶排序的思想

  1. 对比所有数据个位,进行排序。
  2. 将上面结果对比所有数据十位,进行排序。
  3. 将上面结果对比所有数据百位,进行排序。
    以此类推
void radixsort(int *a, int n) {
  int i, b[MAX], m = a[0], exp = 1;

  for (i = 1; i < n; i++) {
    if (a[i] > m) {
      m = a[i];
    }
  }

  while (m / exp > 0) {
    int bucket[BASE] = { 0 };

    for (i = 0; i < n; i++) {
      bucket[(a[i] / exp) % BASE]++;
    }

    for (i = 1; i < BASE; i++) {
      bucket[i] += bucket[i - 1];
    }

    for (i = n - 1; i >= 0; i--) {
      b[--bucket[(a[i] / exp) % BASE]] = a[i];
    }

    for (i = 0; i < n; i++) {
      a[i] = b[i];
    }

    exp *= 10;
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值