内部排序

lixiangrong
2024-01-29 / 0 评论 / 67 阅读 / 正在检测是否收录...

内部排序

#include <stdio.h>

typedef int elementType; // 将需要操作的数据元素定义别名,方便修改
#define MAX_SIZE 100 // 初始化操作数组的最大容量

// 交换两个元素的值
void swap(elementType *a, elementType *b)
{
    elementType temp = *a;
    *a = *b;
    *b = temp;
}

// 1.直接插入排序(将每个待排序的关键字插入前面已经有序的序列中)
void insetSort(elementType A[], int len)
{
    elementType temp;
    int i,j;
    for (i = 1; i < len; i++) // 依次检查A[1]~A[n-1]
    {
        if(A[i] < A[i-1]) // 若A[i]小于前驱则需要移动
        {
            temp = A[i]; // 暂存当前元素
            for (j = i-1; temp < A[j] && j >= 0; --j)
                A[j+1] = A[j]; // 不断向前遍历、移动,直到不小于左侧元素
            A[j+1] = temp; // 复制到插入位置
        }
    }
}

// 1.2折半插入排序(直接插入排序是边比较边移动元素,而折半插入是把比较和移动分离,
// 即先用折半查找确定元素的待插入位置,然后统一移动待插入位置后的所有元素)
void binaryInsertSort(elementType A[],int len)
{
    elementType temp; // 定义临时变量暂存待插入元素
    int low,high,mid; // 定义折半查找定位指针
    for (int i = 1; i < len; i++) // 依次将A[1]~A[n-1]插入到前面的有序序列
    {
        temp = A[i]; // 暂存待插入元素
        low = 0,high = i-1; // 设置折半查找的范围
        while (low <= high)
        {
            mid = (low+high)/2;
            if(A[mid] < temp)
                low = mid + 1; // 查找右子表
            else
                high = mid -1; // 查找左子表
        }
        for (int j = i-1; j > high; j--)
            A[j+1] = A[j]; // 统一后移元素,空出插入位置
        A[high+1] = temp; // 插入到指定位置
    }
}

// 2.希尔排序(把待排序序列中相隔某个”增量“的元素组成一个子表,对各个子表直接插入排序,
// 当整个表已经基本有序时,再对全体记录进行一次直接插入排序。)
void shellSort(elementType A[], int len)
{
    elementType temp; // 临时变量暂存待插入元素
    int d,i,j; // d为步长
    for (d = len/2; d >= 1 ; d /=2)
    {
        for (i = d; i <= len; i++)
        {
            if(A[i] < A[i-d])
            {
                temp = A[i];
                for (j = i-d; j >=0 && temp < A[j]; j -= d)
                    A[j+d] = A[j]; // 记录后移,更新插入位置
                A[j+d] = temp; // 插入待插入元素
            }
        }
    }
}

// 3.冒泡排序(从前往后或从后往前两两比较相邻元素的值,若为逆序,则交换它们,直到比较结束)
void bubbleSort(elementType A[], int len)
{
    int flag; // 标记某趟冒泡是否进行了交换
    for (int i = 0; i < len-1 ; i++)
    {
        flag = 0; // 每趟冒泡前把flag置为false
        for (int j = len-1; j > i; j--) // 一趟冒泡
        {
            if(A[j] < A[j-1]) //是否存在逆序
            {
                swap(&A[j],&A[j-1]);
                flag = 1; // 发生交换动作后把flag置为true
            }
        }
        if(!flag) break; // 若某趟未进行交换操作,则排序结束
    }
}

// 快排划分
int partition(int A[], int low, int high)
{
    int pivot = A[low]; //第一个元素作为基准
    while (low < high)
    {
        while (low < high && A[high] >= pivot)
            --high;
        A[low] = A[high]; // 比基准小的移动到左端
        while (low < high && A[low] <= pivot)
            ++low;
        A[high] = A[low]; // 比基准大的移动到右端
    }
    A[low] = pivot;
    return low; // 返回存放基准的最终位置
}

// 4.快速排序(快速排序是基于分治法的,在待排序表中任取一个元素作为枢纽或基准,
// 通过一趟排序划分为两部分,小于基准的元素放到基准左边,大于的放到右边,
// 这样就确定了一个元素的位置,不断划分,不断移动,递归上述过程直到有序。)
void quickSort(int A[], int low, int high)
{
    if (low < high)
    {
        int pivotPos = partition(A, low, high); // 划分
        quickSort(A, low, pivotPos - 1); // 划分左子表
        quickSort(A, pivotPos + 1, high); // 划分右子表
    }
}

// 5.简单选择排序(每趟在后面n-i+1个待排序元素中选出最小的元素,
// 作为有序子序列的第i个元素,直到n-1趟做完只剩1个,就不必再选了。)
void selectSort(elementType A[], int len)
{
    int i, j,min;
    for (i = 0;i < len-1;i++) // 最后剩一个不用处理,所以是i < n-1
    {
        min = i;
        for ( j = i+1; j < len; j++)
        {
            if (A[j] < A[min])
                min = j;
        }
        if (min != i)
            swap(&A[i],&A[min]);
    }
}

// 调整堆
void adjustHeap(elementType A[],int i,int len)
{
    A[0] = A[i]; // 暂存根节点(若A[0]元素有实际意义,也可用临时变量)
    for (int k = 2*i; k <= len; k *=2) // k *=2表示沿着较大的子结点向下筛选
    {
        if(k < len && A[k] < A[k+1])
            k++; // 记录下最大的孩子结点的索引值
        if(A[0] >= A[k])
            break; // 如果满足大根堆(根节点不小于最大的孩子)则退出循环无需继续调整
        A[i] = A[k]; // 将最大的元素调节到双亲节点上
        i = k; // 修改索引,继续筛选
    }
    A[i] = A[0]; // 将被筛选的结点放入最终位置
}

// 建立大根堆
void buildMaxHeap(elementType A[],int len)
{
    for (int i = len/2; i > 0; i--)
        adjustHeap(A,i,len);
}

// 6.堆排序(大根堆:二叉树根节点大于左右孩子,小根堆则小于;将数组视为顺序存储的树,
// 利用堆这一特性,创建堆,调整堆,每调整一轮都从中选出了最大值,不断将堆顶元素放入堆底。)
void heapSort(elementType A[],int len)
{
    // 1.初始化大根堆
    buildMaxHeap(A,len);
    // 2.不断的调整堆,并且把堆顶元素和堆底元素交换,堆不断缩小
    for (int i = len; i > 1; i--)
    {
        swap(&A[1],&A[i]); //将大根堆堆顶元素放入堆底
        adjustHeap(A,1,i-1); // 不断的调整缩小的堆,直到最大的元素依次在堆底
    }
}

elementType B[MAX_SIZE]; // 定义一个辅助数组,用于归并排序的归并操作
// 归并操作
void merge(elementType A[],int low,int mid,int high)
{
    int i,j,k;
    for (k = low;k <= high;k++)
        B[k] = A[k]; // 将A中的元素复制到B中
    for (i = low,j = mid+1,k = i; i <= mid && j <= high; k++)
    {
        if(B[i] <= B[j])
            A[k] = B[i++];
        else
            A[k] = B[j++];
    }
    while (i<=mid) // 若左表剩余,复制回A表尾部
        A[k++] = B[i++];
    while (j<=high) // 若右表剩余,复制回A表尾部
        A[k++] = B[j++];
}

// 7.二路归并排序(归并排序是基于归并操作实现的,每次归并将相邻的两个有序序列归并成一个)
void mergeSort(elementType A[],int low,int high)
{
    if(low < high)
    {
        int mid = (low+high)/2; // 从中间划分为两个子序列
        mergeSort(A,low,mid); // 对左侧子序列递归排序
        mergeSort(A,mid+1,high); // 对右侧子序列递归排序
        merge(A,low,mid,high); // 合并相邻的两个有序的序列
    }
}

// 打印数组元素,从index下标开始打印len个长度
void printArray(elementType A[],int index,int len)
{
    // 判断数组是否越界
    if(index < 0 || index + len > MAX_SIZE)
    {
        printf("Array Index OutOf Bounds Exception!");
        return;
    }
    for (int i = index; i < index + len; ++i)
    {
        printf("%d",A[i]);
        if(i < index + len - 1)
            printf(",");
    }
    printf("\n");
}

int main()
{
    // 1.直接插入排序
    elementType A[MAX_SIZE] = {49,38,65,97,76,13,27,49};
    insetSort(A,8);
    printArray(A,0,8);

    // 1.1折半插入排序
    elementType A1[MAX_SIZE] = {49,38,65,97,76,13,27,49};
    binaryInsertSort(A1,8);
    printArray(A1,0,8);

    // 2.希尔排序
    elementType B[MAX_SIZE] = {0,49,38,65,97,76,13,27,49};
    shellSort(B,8);
    printArray(B,1,8);

    // 3.冒泡排序
    elementType C[MAX_SIZE] = {49,38,65,97,76,13,27,49};
    bubbleSort(C,8);
    printArray(C,0,8);

    // 4.快速排序
    elementType D[MAX_SIZE] = {49,38,65,97,76,13,27,49};
    quickSort(D,0,7);
    printArray(D,0,8);

    // 5.简单选择排序
    elementType E[MAX_SIZE] = {49,38,65,97,76,13,27,49};
    selectSort(E,8);
    printArray(E,0,8);

    // 6.堆排序
    elementType F[MAX_SIZE] = {0,49,38,65,97,76,13,27,49};
    heapSort(F,8);
    printArray(F,1,8);

    // 7.归并排序
    elementType G[MAX_SIZE] = {49,38,65,97,76,13,27,49};
    mergeSort(G,0,7);
    printArray(G,0,8);

    return 0;
}
0

评论 (0)

取消