C语言实现常见的几种排序算法

一、冒泡排序(Bubble Sort)

工作原理:它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。

void bubble_sort(int arr[], int n)
{
    int i, j;
    int temp;

    for(i=0;i<n;i++)
        for(j=0;j<n-i-1;j++)
            if (arr[j] < arr[j + 1])
            {
                temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
}

二、选择排序(Selection sort)

工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

     

void selection_sort(int arr[], int n)
{
    int i,j;
    int temp;

    for (i = 0; i < n-1; i++)
        for (j = i + 1; j < n; j++)
            if (arr[i] < arr[j])
            {
                temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
}

三、插入排序(Insertion Sort)

工作原理:是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

void insertion_sort(int arr[], int n)
{
    int temp;
    int i, j;
    for (i = 1; i < n; i++)
    {
        temp = arr[i];
        for (j = i; j>0&&(temp>arr[j-1]); j--)
                arr[j] = arr[j-1];
        arr[j] = temp;
    }
}

四、希尔排序(shell sort)

希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。希尔排序是非稳定排序算法。

希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。

希尔排序是基于插入排序的以下两点性质而提出改进方法的:

  • 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率
  • 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位

void ShellSort(int arr[], int n)
{
    int gap, i, j;
    int temp;
    gap = n / 2;
    while (gap >= 1)
    {
        for (i = gap; i < n; i++)
        {
            temp = arr[i];
            j = i - gap;
            while ((j >= 0) && (temp > arr[j]))
            {
                arr[j + gap] = arr[j];
                j -= gap;
            }
            arr[j+gap] = temp;
        }
        gap /= 2;
    }
}

五、归并排序(Merge sort)

归并排序的实现分为 递归实现 与 非递归(迭代)实现 。递归实现的归并排序是算法设计中分治策略的典型应用,我们将一个大问题分割成小问题分别解决,然后用所有小问题的答案来解决整个大问题。非递归(迭代)实现的归并排序首先进行是两两归并,然后四四归并,然后是八八归并,一直下去直到归并了整个数组。  

归并排序算法主要依赖归并(Merge)操作。归并操作指的是将两个已经排序的序列合并成一个序列的操作,归并操作步骤如下:

 1.申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列

2.设定两个指针,最初位置分别为两个已经排序序列的起始位置

3.比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置

4.重复步骤3直到某一指针到达序列尾

5.将另一序列剩下的所有元素直接复制到合并序列尾

递归实现:

void MergeSort(int arr[], int n)
{
    int * reg;
    reg = (int *)malloc(sizeof(int)*n);
    MergeSort_recursive(arr, reg, 0, n - 1);
/* 其实最后将reg[]传递给arr[]就可以了,下面的是为了看清归并的每一个步骤 */
    for (int i = 0; i < n; i++)
        arr[i] = reg[i];
    free(reg);
}

void MergeSort_recursive(int arr[], int reg[], int start, int end)
{
    if (start == end)
    {
        reg[start] = arr[start]; 
        printf("%d:%d,%d\n", start, arr[start], reg[start]);
        putchar('\n');
    }
    else
    {
        int len = end - start, mid = (len >> 1) + start;
        int start1 = start, end1 = mid;
        int start2 = mid + 1, end2 = end;
        MergeSort_recursive(arr, reg, start1, end1);
        MergeSort_recursive(arr, reg, start2, end2);
        int k = start;
        while (start1 <= end1 && start2 <= end2)
            reg[k++] = arr[start1] < arr[start2] ? arr[start1++] : arr[start2++];
        while (start1 <= end1)
            reg[k++] = arr[start1++];
        while (start2 < end2)
            reg[k++] = arr[start2++];
        for (k = start; k <= end; k++)
        {
            printf("%d:%d,%d\n", k, arr[k], reg[k]);
            arr[k] = reg[k];
        }
        putchar('\n');
    }
}

迭代实现:
int minumum(int x, int y)
{
    return x < y ? x : y;
}
void MergeSort2(int arr[], int n)
{
    int * a = arr;
    int * b = (int *)malloc(n * sizeof(int));
    int seg, start;
    printf("a = %pt,b = %pt\n", a, b);
    for (seg = 1; seg < n; seg *= 2)
    {
        for (start = 0; start < n; start += 2 * seg)
        {
            int low = start, mid = minumum(start + seg, n), high = minumum(start + 2 * seg, n);
            int k = low;
            int start1 = low, end1 = mid;
            int start2 = mid, end2 = high;
            while (start1 < end1&&start2 < end2)
                b[k++] = a[start1] < a[start2] ? a[start1++] : a[start2++];
            while (start1 < end1)
                b[k++] = a[start1++];
            while (start2 < end2)
                b[k++] = a[start2++];
            for (k = start; k < high; k++)
                a[k] = b[k];
        }
    }
    free(b);
}

六、快速排序(quick sort)

在区间中随机挑选一个元素作基准,将小于基准的元素放在基准之前,大于基准的元素放在基准之后,再分别对小数区与大数区进行排序。

快速排序使用分治策略来把一个序列分为两个子序列。步骤为:

  1. 从序列中挑出一个元素,作为"基准"(pivot).
  2. 把所有比基准值小的元素放在基准前面,所有比基准值大的元素放在基准的后面(相同的数可以到任一边),这个称为分区(partition)操作。
  3. 对每个分区递归地进行步骤1~2,递归的结束条件是序列的大小是0或1,这时整体已经被排好序了。

递归实现:

void swap(int * x, int * y)
{
    int t = *x;
    *x = *y;
    *y = t;
}
void QuickSort_recursive(int arr[],int start,int end)
{
    if (start < end)
    {
        int mid = arr[end];
        int left = start, right = end - 1;
        while (left < right)
        {
            while (arr[left] < mid&&left < right)
                left++;
            while (arr[right] >= mid && left < right)
                right--;
            swap(&arr[left], &arr[right]);

            left++;
            right--;
        }
        if(arr[left]>arr[end])
            swap(&arr[left], &arr[end]);
        if (left)
            QuickSort_recursive(arr, start, left - 1);
        QuickSort_recursive(arr, left + 1, end);
    }
}
void QuickSort1(int arr[], int n)
{
    QuickSort_recursive(arr, 0, n - 1);
}

迭代实现:

typedef struct {
    int start, end;
}Range;
Range New_Range(int s, int e)
{
    Range r;
    r.start = s;
    r.end = e;
    return r;
}
void QuickSort2(int arr[], int n)
{
    if (n <= 0)
        return;
    Range * r = (Range *)malloc(n * sizeof(Range));
    int p = 0;
    r[p++] = New_Range(0, n - 1);
    while (p)
    {
        printf("p = %d\n", p);
        Range range = r[--p];
        if (range.start >= range.end)
            continue;
        int mid = arr[(range.start + range.end) / 2];
        int left = range.start, right = range.end;
        do {
            while (arr[left] < mid)
                left++;
            while (arr[right] > mid)
                right--;
            if (left <= right)
            {
                swap(&arr[left], &arr[right]);
                left++;
                right--;
            }
        } while (left <= right);
        if (range.start < right)
            r[p++] = New_Range(range.start, right);
        if (range.end > left)
            r[p++] = New_Range(left, range.end);
    }

    free(r);
}

猜你喜欢

转载自blog.csdn.net/weixin_44165923/article/details/86523252