C语言基础排序算法

一、常见的几种排序算法

  1、冒泡排序,原理自行搜索,直接上代码

  比较相邻元素的大小关系,并判断是否进行交换

int main()
{
    // 冒泡排序 
    int i=0,len = 10;
    int M, N,tmp;
    int arr[10]={4,7,2,5,3,1,8,9,12,10};
    
    printf("sort before arr: ");
    for(i=0;i<10;i++)
    {
        printf("%d ",arr[i]);
    } 
    printf("\n");
    
    // 冒泡排序
    for(M = len-1;M>0;M--)  // 最外轮排序 ,每排好一个元素,排序次数减少一次
    {    
        for(N=0;N<M;N++) // 元素之间大小判断
        {
            if(arr[N]>arr[N+1])
            {
                tmp = arr[N+1];
                arr[N+1] = arr[N];
                arr[N] = tmp;
            }
        } 
    }
    
    printf("sort after arr: ");
    for(i=0;i<10;i++)
    {
        printf("%d ",arr[i]);
    } 
    printf("\n");
    return 0;
}
View Code

  2、选择排序

  选择排序的基本思想是:第一次从待排序的数据中选出最小(或最大)的一个数据,存放在序列的起始位置;第二次再从剩余的未排序数据中寻找到最小(大)数据,存放到已排序好的数据的后面。以此类推,直到全部待排序的数据个数为零

int main()
{
    // 使用选择排序 
    int i=0,len = 10;
    int M, N,tmp,index;
    int arr[10]={4,7,2,5,3,1,8,9,12,10};
    
    printf("sort before arr: ");
    for(i=0;i<10;i++)
    {
        printf("%d ",arr[i]);
    } 
    printf("\n\n");
    
    for(M=0;M<len-1;M++)
    {
        index = M;
        for(N=M+1;N<len;N++)
        {
            if(arr[N] < arr[index])
            {
                index = N;   // 记录最小元素的位置
            }
        }
        tmp = arr[index]; // 元素交换
        arr[index] = arr[M];
        arr[M] = tmp;
    }
    
    printf("sort after arr: ");
    for(i=0;i<10;i++)
    {
        printf("%d ",arr[i]);
    } 
    printf("\n\n");
        
    return 0;
} 
View Code

  3、插入排序

插入排序顾名思义就是把未排序的数字插入到已经排序的序列的正确位置。

  选择一个基准元素,并与后面的最小(最大的元素逐一比较,将后面序列中的元素,放在前面,组成有序的序列)

// 使用for循环移动完所有元素,再插入待排元素

// method one
for(i=1;i<len;i++)
{
     tmp = arr[i];
     for(j=i-1;tmp<arr[j] && j>=0;--j)
     {
          arr[j+1] = arr[j];   // 移动所有元素
     }
     arr[j+1] = tmp; // 插入待排的元素
}
 


int main()
{
    int arr[10] ={4,7,2,5,3,1,8,9,12,10};
    
    int i=0,j, len =10,tmp;
    printf("arr: ");
    for(i=0;i<len;i++)
    {
        printf("%d ",arr[i]); 
    }
    printf("\n\n");

    // method two  交换相邻元素
    for(i=1;i<len;i++)   
    {
        for(j=i;j>0;j--)
        {
            if(arr[j-1] > arr[j])
            {
                tmp = arr[j];
                arr[j] = arr[j-1];
                arr[j-1] = tmp;
            }
        }
    }

    printf("sort after arr: ");
    for(i=0;i<len;i++)
    {
        printf("%d  ", arr[i]);
    }
    printf("\n\n");

    return 0;

}
View Code

   4、希尔排序

  在插入排序的基础上将数据逐步划分,并把划分后的数据,进行排序。而最后一遍排列比较有顺序的数据(后面数据有序,因此排列速度可以很快);

int main()
{
    int arr[15]={3,6,14,2,5,9,7,30,24,17,31,27,22,10,15};
    int len =15, i,j, gap,tmp;
    
    printf("sort before arr: ");
    for(i=0;i<len;i++)
    {
        printf("%d ", arr[i]);
    }
    printf("\n\n");

    // 进行希尔排序 shell sort
    for(gap=len/2;gap>0;gap= gap/2)   // 将数据划分
    {
        for(i=gap;i<len;i++)   // 排列部分数据
        {
            tmp = arr[i];  // 对每个元素排列
            for(j=i-gap;arr[j]>tmp && j>=0 ;j-= gap)
            {
                arr[j+gap]=arr[j];
            }
            arr[j+gap] = tmp;
        }
    }
    
    printf("After sort arr: ");
    for(i=0;i<len;i++)
    {
        printf("%d  ", arr[i]);
    }
    printf("\n");

    printf("Hello world");
    return 0;
}
View Code

  5、快速排序

  使用两个索引(数组下标),从两边开始扫描,再去一个元素作为基准,小于这个基准的放在左边,大于这个基准的放在右边;这个基准逐渐移动,便可以完成排序

// 获取中间基准元素的索引
int get_mid(int b[], int left, int right){
    int pivot = b[left];
    while(left<right)    
    {
        while(b[right]>=pivot && left < right)   right--;
        b[left] = b[right];
        while(b[left] <= pivot && left < right) left++;
        b[right]=b[left];
    }
    b[left] = pivot;
    return left;
}

// 拿到基准后
void quick_sort(int b[], int left, int right)
{
    if(left < right)
    {
        int mid = get_mid(b, left, right);
        quick_sort(b,left,mid-1);       // 左右交替排序
        quick_sort(b, mid+1, right);  // 左右交替排序
    }
}


int main()
{
    int arr[15]={3,6,14,2,5,9,7,30,24,17,31,27,22,10,15};
    int len =15, i,j, cmp,tmp;
    int L,R;
    printf("sort before arr: ");
    for(i=0;i<len;i++)
    {
        printf("%d ", arr[i]);
    }
    printf("\n\n");
    
    // 快速排序
    cmp = arr[0];
    L = 0, R=14;
    //for(i=0;i<len;i++)
    
    quick_sort(arr, 0,14);
    
    
    printf("After sort arr: ");
    for(i=0;i<len;i++)
    {
        printf("%d  ", arr[i]);
    }
    printf("\n");

    printf("Hello world");
    return 0;
}
        
View Code

  6、归并排序

  将待排序列进行逐步2等份划分,划分后的左右序列再划分,直到每个序列都未一个元素,一个元素就算有序的;这样递归下去同时记录序列中间下标mid;

#include <stdio.h>
#include <stdlib.h>

// 打印数组
void pfun(int *arr,int len)
{
    printf("arr: ");
    for(int i=0;i<len;i++)
    {
        printf("%d  ", arr[i]);
    }
    printf("\n");
}
// 合并
void merge(int arr[],int aux[],int left,int mid,int right)
{
    // 标记左半区第一个未排序的元素
    int l_pos = left;
    // 标记右半区第一个未排序的元素
    int r_pos = mid+1;
    // 临时数组元素下标
    int pos = left;
    // 合并
    while(l_pos <= mid && r_pos <= right)
    {
        if(arr[l_pos] < arr[r_pos])   // 左半区域第一个元素小
        {
            aux[pos] = arr[l_pos];
            pos++;
            l_pos++;
        }else{                      // 右半区域第一个元素小
            aux[pos] = arr[r_pos];
            pos++;
            r_pos++;
        }
    }
    // 合并左半区配合上面的while条件,下面这两个while循环同时只能满足一条
    // 合并左半区剩余的元素
    while(l_pos <= mid)
    {
        aux[pos] = arr[l_pos];
        pos++;
        l_pos++;
    }
    // 合并右半区剩余的元素
    while(r_pos <= right)
    {
        aux[pos] = arr[r_pos];
        pos++;
        r_pos++;
    }
    // 将临时数组中的元素拷贝至原来的数组中
    while(left<= right)
    {
        arr[left] = aux[left];
        left++;
    }
}
// 归并排序的实际函数
void msort(int* arr,int * aux,int left,int right)
{
    // 如果只有一个,那么就不需要划分了;
    // 只有一个元素,那么这个元素就是有序的;
    if(left < right)
    {
        // 找中间元素
        int mid = (left+right)/2;
        // 递归划分左半区
        msort(arr,aux,left,mid);
        // 递归划分右半区
        msort(arr,aux,mid+1, right);
        // 合并已经排序的元素
        merge(arr,aux,left,mid,right);
    }
}
// 归并排序函数的入口
void mergesort(int* arr, int len)
{
    // 分配一个辅助数组
    int* aux = (int*)malloc(len*sizeof(int));
    if(aux){
        msort(arr,aux,0,len-1);
        free(aux);
    }
    else
        printf("failed to allocate memory");
}

int main()
{
    int arr[]={8,3,6,4,2,1,5,7};
    pfun(arr,8);
    mergesort(arr,8);
    pfun(arr,8);
    printf("Hello World\n");
    return 0;
}
View Code

  这里使用递归的方式,也可以使用for循环来做,后续再补充;

   7、堆排序

  堆排序针对完全二叉树类型;如果根节点的元素都大于子节点的元素,那么这个堆是大顶堆;相反根节点元素最小,那么称为小顶堆;

         

    在使用堆排序之前,首先将待排数组中元素,建立一个堆的关系,然后,维护堆的规则,得到最大元素在根节点;然后,将堆中最后一个元素与堆的根节点元素交换,这时比较小的元素在根节点,因此再次维护堆,使得最大元素移动至根节点,将之前根节点最大元素存放至数组最后端;

  大顶堆维护:

    选取一个节点,判断子结点元素是否大于节点元素,如果大于节点元素就将子节点元素和父节点元素交换;一次递归每个节点,使得整个堆满足大顶堆的条件;

#include <stdio.h>

/* 维护大顶堆的性质
 * @param arr:堆的数组
 * @param len: 数组长度
 * @param index: 待排元素数组的下标
 * */
void heapify(int arr[], int len,int index)
{
    int largest = index; // 假设父节点元素为待排元素
    int lson = index * 2 + 1; // 左孩子的节点下标
    int rson = index * 2 + 2; // 右孩子的节点下标
    
    if(lson < len && arr[largest] < arr[lson])
    {
        largest = lson;
    }
    if(rson < len && arr[largest] < arr[rson])
    {
        largest = rson;
    }
    // 上面操作后,我们获得较大元素的

    if(largest != index)  // 说明父节点及子节点的元素不满足大顶端规则
    {
        int tmp = arr[largest]; // 保存子孩子较大的节点,以及交换
        arr[largest] = arr[index];
        arr[index] = tmp;
        heapify(arr,len,largest);   // 再次排列子孩子节点元素
    }
}


// 堆排序的入口
void heap(int arr[],int len)
{
    // 建堆
    int i=0;
    for(i=len/2 -1;i>=0;i--) {
        heapify(arr,len,i);
    }   
    // 建完堆以后,第一个元素最大,最后一个元素最小

    // 排序
    for(i=len-1;i>0;i--)
    {
        int tmp = arr[0];  // 交换最后一个元素和第一个元素
        arr[0] = arr[i];
        arr[i] = tmp;
        heapify(arr,i,0);   // 重新维护堆顺序
    }

}
int main()
{
    int i=0;
    int arr[] = {2,3,8,6,7,9,1,4,14,5};
    printf("arr: ");
    for(i=0;i<10;i++)
    {
        printf("%d  ", arr[i]);
    }
    printf("\n");

    heap(arr, 10);
    
    printf("After sort arr: ");
    for(i=0;i<10;i++)
    {
        printf("%d  ",arr[i]);
    }
    printf("\n");
    return 0;
}
View Code

 

 

 

 

 

  计数排序

   相对于特殊的数据形式,数据没有相同的项;可以将数据放到对应的位置,达到数据排序的问题;

void main()
{
    int i=0;
    int arr[10]={4,6,2,1,5,3,9,7,10,8};
    
    int ar[10];
    for(i=0;i<10;i++)
    {
        ar[arr[i]-1] = arr[i];   // 根据数值,将数据放置对应的位置
    }

    printf("sort after arr: \n");
    for(i=0;i<10;i++)
    {
        printf("%d ",ar[i]);
    }

}
View Code

 

posted @ 2021-08-04 11:01  笑不出花的旦旦  阅读(630)  评论(0)    收藏  举报