经典排序算法

//1.冒泡排序:
#pragma once
#include<stdio.h>

void Swap5(int* a, int* b)
{
    int c = *a;
    *a = *b;
    *b = c;
}

void Print5(int arr[], int size)
{
    for (int i = 0; i < size; i++)
    {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

//冒泡排序
//思想:
//9 5 2 7 4 1 3 
//1.两个数之间相互比较大小,每次将较大的值的数字放在后面
//2.循环整个数组,一次遍历后就将最大值放在了最后
//3.在--size,在次循环
void Sort5(int arr[], int size)
{
    while (size)
    {
        for (int i = 1; i < size; i++)
        {
            if (arr[i - 1] > arr[i])
            {
                Swap5(&arr[i - 1], &arr[i]);
            }
        }
        size--;
    }
}

void Text5()
{
    int arr[] = { 9,5,2,7,4,1,3 };
    int size = sizeof(arr) / sizeof(arr[0]);
    Print5(arr, size);
    Sort5(arr, size);
    Print5(arr, size);
}

//////////////////////////////////////////////////////////////////////////////////
//2.堆排序
#pragma once
#include<stdio.h>

void Swap(int* a, int* b)
{
    int i = *a;
    *a = *b;
    *b = i;
}

//向下调整(找最大)
void Heapify(int arr[], int size, int index)
{
    while (1)
    {
        int leftindex = (2 * index) + 1;
        int rightindex = (2 * index) + 2;
        //如果左孩子不存在,则右孩子也一定不存在
        if (leftindex >= size)
        {
            return;
        }
        //判断是否有右孩子并找到最大孩子
        int maxindex = leftindex;
        if (rightindex < size && arr[rightindex] > arr[leftindex])
        {
            maxindex = rightindex;
        }
        //比较最大孩子与根的大小
        if (arr[maxindex] >= arr[index])
        {
            Swap(&arr[maxindex], &arr[index]);
        }
        index = maxindex;
    }
}
//3.创建堆
void CreatHeapify(int arr[], int size)
{
    //将数组逻辑上的储存看作二叉树
    //从最后一个非叶子节点开始一次从下到上一次调整二叉树,使二叉树满足堆的特点

    for (int i = (size - 2) / 2; i >= 0; i--)
    {
        //这里的传参有点问题?
        Heapify(arr, size, i);
    }
}

//二叉树的堆排序(升序)
void Sort(int arr[], int size)
{
    //将数组创建成为堆
    CreatHeapify(arr, size);
    //每次取出堆顶元素(最大值)与最后一个元素互换,size--
    //在一次从新数组的堆顶开始一次下调,建成新堆
    //循环,直到size = 0
    while (size > 0)
    {
        Swap(&arr[0], &arr[size - 1]);
        size--;
        Heapify(arr, size, 0);
    }
}

void Print(int arr[], int size)
{
    for (int i = 0; i < size; i++)
    {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

void Text1()
{
    int arr[] = { 9,3,1,2,6,5,7,4,9,0,3 };
    int size = sizeof(arr) / sizeof(arr[0]);
    Print(arr, size);
    Sort(arr, size);
    Print(arr, size);
}

//////////////////////////////////////////////////////////////////////////////////
//3.插入排序
#pragma once

#include<stdio.h>

void Print3(int arr[], int size)
{
    for (int i = 0; i < size; i++)
    {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

void Swap3(int* a, int* b)
{
    int i = *a;
    *a = *b;
    *b = i;
}

//9, 5, 2, 7, 4, 1
//5, 9, 2, 7, 4, 1

void Insert(int arr[], int size)
{
    for (int i = 0; i < size; i++)
    {
        for (int j = i; j > 0 ; j--)
        {
            if (arr[j] < arr[j - 1])
            {
                Swap(&arr[j], &arr[j - 1]);
            }
            else
            {
                break;
            }
        }
    }
}

void Text3()
{
    int arr[] = { 9, 5, 2, 7, 4, 1 };
    int size = sizeof(arr) / sizeof(arr[0]);
    Print3(arr, size);
    Insert(arr, size);
    Print3(arr, size);
}
//////////////////////////////////////////////////////////////////////////////
//4.归并排序
#pragma once
#include<stdio.h>
#include<stdlib.h>


void Swap7(int* a, int* b)
{
    int c = *a;
    *a = *b;
    *b = c;
}

void Print7(int arr[], int size)
{
    for (int i = 0; i < size; i++)
    {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

//归并排序
//思想:
//1.将数组分成已经有序的两个数组,在合并这两个数组
//2.如果整个数组都是无序的,就在将两个数组分别分为两个数组,
//3.直到所分的数组中只有一个元素的时候,那么它肯定是有序的
//4.然后在一次合并这些分开的数组
void Merge(int array[], int low, int mid, int high, int extra[]) {
    // [low, high)

    int i = low;    // [low, mid)
    int j = mid;    // [mid, high)
    int k = low;    // extra[low, high)

    while (i < mid && j < high) {
        if (array[i] <= array[j]) {    // = 保证了稳定性
            extra[k++] = array[i++];
        }
        else {
            extra[k++] = array[j++];
        }
    }

    while (i < mid) {
        extra[k++] = array[i++];
    }

    while (j < high) {
        extra[k++] = array[j++];
    }

    for (int x = low; x < high; x++) {
        array[x] = extra[x];
    }
}

// [low, high)
void MergeSortInner(int array[], int low, int high, int extra[]) {
    // 2. 直到 size == 1 || size == 0
    if (low >= high) {
        // size == 0
        return;
    }

    if (low + 1 == high) {    // [3, 4)
        // size == 1
        return;
    }

    // 1. 平均切割
    int mid = low + (high - low) / 2;
    // 2. 分治处理左右两个小区间
    MergeSortInner(array, low, mid, extra);    // [low, mid)
    MergeSortInner(array, mid, high, extra);    // [mid, high)
    // 3. 合并两个有序数组
    Merge(array, low, mid, high, extra);
}

void Sort7(int array[], int size) {
    int *extra = (int *)malloc(sizeof(int)* size);
    MergeSortInner(array, 0, size, extra);
    free(extra);
}

void Text7()
{
    int arr[] = { 9,5,2,7,4,1,3 };
    int size = sizeof(arr) / sizeof(arr[0]);
    Print7(arr, size);
    Sort7(arr, size);
    Print7(arr, size);
}
////////////////////////////////////////////////////////////////////////////////
//5.快排
#pragma once

#include<stdio.h>

void Swap4(int* a, int* b)
{
    int c = *a;
    *a = *b;
    *b = c;
}

void Print4(int arr[], int size)
{
    for (int i = 0; i < size; i++)
    {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

//挖坑
//思想:
//1.为数组找一个基准值并保存下来(我们取最右边的数字) 
//2.begin找大于基准值的数并赋值给end下标所在的数
//3.end找小于基准值的数并赋值给begin下标所在的数
//4.当begin 与 end 的值相等的时候,退出循环
//5.将保存的基准值赋值给 begin 下标所在数字,并返回下标的值,就为分割的下标
int Partition_1(int arr[], int left, int right)
{
    //找基准值(以最右边的right作为基准值)
    int begin = left;
    int end = right;
    int temp = arr[right];
    while (begin < end)
    {
        while (begin < end && arr[begin] <= temp)
        {
            begin++;
        }
        //这里找到比基准值大的数
        arr[end] = arr[begin];
        while (begin < end && arr[end] >= temp)
        {
            end--;
        }
        //这里找到比基准值小的数
        arr[begin] = arr[end];
    }
    arr[begin] = temp;
    return begin;
}

//Hover
//思想:
//1.与挖坑相同,需要先定义一个基准值(我们取最右边的数字)
//2.由 begin 开始寻找大于基准值的数
//3.end 寻找小于基准值的数字
//4.将 begin 与 end 交换,确保大于基准值的数字在右边,小于基准值的在左边
//5.当 begin 与 end 相等的时候退出循环并 将基准值与 begin 下标所在数字与基准值交换
//6.返回下标,就是分割的下标
int Partition_2(int arr[], int left, int right)
{
    int begin = left;
    int end = right;
    int temp = arr[right];
    while (begin < end)
    {
        while (begin < end && arr[begin] <= temp)
        {
            begin++;
        }
        //这里保证了出来的arr[begin]值一定大于基准值temp
        while (begin < end && arr[end] >= temp)
        {
            end--;
        }
        //这里保证了出来的arr[end]值一定小于基准值temp
        //交换这两个值,保证大于基准值的在右边,小于基准值的在左边
        Swap4(&arr[begin], &arr[end]);
    }
    //当 begin 与 end 的值相等的时候退出循环,
    //及保证了分治的条件,在将基准值与 begin 下标的数字交换位置
    Swap(&arr[begin], &arr[right]);
    //这里的基准值必须取rihgt下标所在数,不能用保存的变量temp,否则就会改变数组中的元素
    return begin;
}
//前后下标
//思想:
//9 5 2 7 4 1
//1.同样的,需要先定义一个基准值(我们取最右边的数字)
//2.由 i 开始寻找小于基准值的数,index 作为标记,在 index 的左边都是小于基准值的
//3.找到后将 i 与 index 交换,后 ++index ,确保小于基准值的数字在左边,大于于基准值的在右边
//5.将数组内的数字都寻找完的时候退出循环并 将基准值与 index 下标所在数字交换
//6.返回下标,就是分割的下标
int Partition_3(int arr[], int left, int right)
{
    int index = left;
    for (int i = left; i < right; i++) 
    {
        if (arr[i] < arr[right]) 
        {
            Swap(&arr[i], &arr[index]);
            index++;
        }
    }

    Swap(&arr[index], &arr[right]);

    return index;
}

void Sort4(int arr[], int left, int right)
{
    if (left == right)
    {
        return;
    }
    if (left > right)
    {
        return;
    }
    int index = Partition_2(arr, left, right);
    //这里自己写的时候出错了,原因:
    //分治的时候没有找准边界,边界应该是 左闭右开 的范围

    //(可以这样理解,当我们分割的时候,下标为 idex 的数字已经在它应该存在的位置了,所以不必在进行排序)

    //将index - 1 / index + 1 直接写为 idex
    //导致程序进入了循环状态
    Sort4(arr, left, index - 1);
    Sort4(arr, index + 1, right);
}

void Text4()
{
    int arr[] = { 9,5,2,7,4,1,3 };
    int size = sizeof(arr) / sizeof(arr[0]);
    Print4(arr, size);
    Sort4(arr, 0, size - 1);
    Print4(arr, size);
}
//////////////////////////////////////////////////////////////////////////////////
//6.选择排序
#pragma once

#include<stdio.h>

void Swap2(int* a, int* b)
{
    int i = *a;
    *a = *b;
    *b = i;
}

//9, 5, 2, 7, 4, 1
void Select(int arr[], int size)
{
    for (int i = 0; i < size; i++) {
        // 有序 [size - i, size - 1]
        // 无序 [0, size - 1 - i]
        int max = 0;
        // 要查找整个无序区间的最大值的下标
        int j = 0;
        for (j; j <= size - 1 - i; j++) {
            if (arr[j] >= arr[max]) {
                max = j;
            }
        }
        // maxIdx 记录着无序区间部分最大的数的下标
        // 和无序区间的最后一个位置的数进行交换
        Swap2(&arr[max], &arr[size - 1 - i]);
    }
    
    //在这里用while也可以
    //while (size > 0)
    //{
    //    int max = 0;
    //    for (int j = 0; j < size; j++)
    //    {
    //        if (arr[max] < arr[j])
    //        {
    //            max = j;
    //        }
    //    }
    //    Swap2(&arr[max], &arr[size - 1]);
    //    size--;
    //}
}

void Print2(int arr[], int size)
{
    for (int i = 0; i < size; i++)
    {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

void Text2()
{
    int arr[] = { 199,84,3,77,4,6,2 };
    int size = sizeof(arr) / sizeof(arr[0]);
    Print2(arr, size);
    Select(arr, size);
    Print2(arr, size);
}
//////////////////////////////////////////////////////////////////////////////////
//7.希尔排序
#pragma once

#include<stdio.h>

void Swap6(int* a, int* b)
{
    int c = *a;
    *a = *b;
    *b = c;
}

void Print6(int arr[], int size)
{
    for (int i = 0; i < size; i++)
    {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

//希尔排序
//思路:
//把记录按下标的一定增量分组,对每组使用直接插入排序算法排序。
//随着增量逐渐减少,每组包含的关键词越来越多。
//当增量减至1时,整个文件恰被分成一组,算法便终止。
void InsertSortWithGap(int array[], int size, int gap) {
    for (int i = 0; i < size; i++) {
        int key = array[i];
        int j;
        for (j = i - gap; j >= 0 && array[j] > key; j -= gap) {
            array[j + gap] = array[j];
        }

        array[j + gap] = key;
    }
}

void Sort6(int array[], int size) {
    int gap = size;
    while (1) {
        gap = gap / 3 + 1;
        // gap = gap / 2;

        InsertSortWithGap(array, size, gap);

        if (gap == 1) {
            break;
        }
    }
}

void Text6()
{
    int arr[] = { 9,5,2,7,4,1,3 };
    int size = sizeof(arr) / sizeof(arr[0]);
    Print6(arr, size);
    Sort6(arr, size);
    Print6(arr, size);
}
////////////////////////////////////////////////////////////////////////////////

 

posted on 2019-08-20 10:40  The_Ocean  阅读(169)  评论(0编辑  收藏  举报

导航