zoukankan      html  css  js  c++  java
  • 经典排序算法

    //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("
    ");
    }
    
    //冒泡排序
    //思想:
    //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("
    ");
    }
    
    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("
    ");
    }
    
    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("
    ");
    }
    
    //归并排序
    //思想:
    //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("
    ");
    }
    
    //挖坑
    //思想:
    //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("
    ");
    }
    
    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("
    ");
    }
    
    //希尔排序
    //思路:
    //把记录按下标的一定增量分组,对每组使用直接插入排序算法排序。
    //随着增量逐渐减少,每组包含的关键词越来越多。
    //当增量减至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);
    }
    ////////////////////////////////////////////////////////////////////////////////
  • 相关阅读:
    无阻塞网络
    带宽、线速、吞吐量
    one-to-all及all-to-all网络通信模式
    CLOS网络架构与FATTREE胖树拓扑
    CLOS网络
    IP分片与重组详解
    原 TCP层的分段和IP层的分片之间的关系 & MTU和MSS之间的关系
    多个方面比较电路交换、报文交换和分组交换的主要优缺点
    地址族与数据序列 (转)
    简单网络搭建与测试 mininet
  • 原文地址:https://www.cnblogs.com/cuckoo-/p/11381587.html
Copyright © 2011-2022 走看看