• 渐增型算法一:插入排序


    一、算法说明

    1、渐增型算法:作为算法的主体是一个循环,逐个处理输入数据,已经处理的部分为问题的解;即按顺序处理问题,当输入数据处理完,问题也就处理了。
    2、算法特点:直观,时间复杂度不友好
    3、个人理解:降低问题维度,将一维的输入数据转化成单个数据,能准确处理单个数据时,遍历整个输入数据即可。

    二、插入排序算法

    1、输入一个乱序的数组,使用插入排序算法,输出升序或者降序数组;
    2、从乱序数组中,逐个取出元素,加入已经排序好的数组,保证新加入的元素不破坏当前数组排序;
    3、将数组排序问题,转化成,单个元素有序插入已经排序数组问题;
    4、问题初始状态:从原始数组中取出第一个元素,作为已排序的数组初始状态;
    5、算法核心:单个元素插入已排序数组,从数组尾部比较,将数据后移,找到该元素对应位置。

    三、基础版本代码实现

    int insertionSortV1(int *array, int len)
    {
        int key, j;
        for (int i = 1; i < len; i++) {
            key = array[i];
            j = i;
            // 将key插入到已经排好序的array[j - 1]中,使array[j]有序;修改判断条件,可以控制顺序
            while (j > 0 && (array[j - 1] > key)) {
                array[j] = array[j -1];
                j--;
            }
            array[j] = key;
        }
        return 0;
    }
    

    四、使用指针优化,扩展通用性

    1、指针使用说明:输入任意类型的数据,提供对应的比较函数,即可以实现排序,参考qsort。
    2、比较函数实现:

    // V2: 输入任意类型的数组,使用指针实现
    int intGreater(void *x, void *y)
    {
        // 需要先对指针类型进行强制转换
        return *(int *)x - *(int *)y;
    }
    
    int charGreater(void *x, void *y)
    {
        // 需要先对指针类型进行强制转换
        return strcmp((char *)x, (char *)y);
    }
    

    3、算法优化实现:

    int insertionSortV2(void *array, int len, int array_size, int (*cmp)(void *, void *))
    {
        int j;
        // array_size 表示数组元素的大小
        void *key = (void *)malloc(array_size);
        memset(key, 0, array_size);
    
        for (int i = 1; i < len; i++) {
            // 利用指针取数
            key = memcpy(key, array + i * array_size, array_size);
            j = i;
            // 将key插入到已经排好序的array[j - 1]中,使array[j]有序
            while ((j > 0) && (cmp(key, array + (j - 1) * array_size) < 0)) {
                // 内存赋值,使用指针
                memcpy(array + j * array_size, array + (j - 1) * array_size, array_size);
                j--;
            }
            memcpy(array + j * array_size, key, array_size);
        }
    
        return 0;
    }
    

    五、双链表的插入排序

    链表的创建和清除参考:双链表:结构体定义、创建、清除
    整体思路与上相同,依旧是逐个处理各节点数据,将其插入已经排好序的链表中。

    /*
     * descrition:双链表的插入排序
     * input:链表头结点指针,结点数据的大小,比较函数
     * output:在原链表上进行排序,成功返回 0
    */
    int insertionSortV3(DOUBLE_LINKED_NODE *doubleLinkNode, int nodeDataSize, int(*cmp)(void *, void *))
    {
        DOUBLE_LINKED_NODE *newNode, *preNode, *posNode;
        void* tempData = (void*)malloc(nodeDataSize);
        // 默认第一个结点有序,逐个处理后续节点
        for (newNode = doubleLinkNode->next; newNode != NULL; newNode = newNode->next) {
            // 节点数据赋值
            memcpy(tempData, newNode->data, nodeDataSize);
            preNode = newNode->pre;
            // posNode 用于标记新节点带插入的位置
            posNode = newNode;
            // 利用前向指针preNode,将新增的节点插入到原来已经排好序的部分链表中
            // 实际上,是将不各节点后移,找到新节点的正确位置
            while ((preNode != NULL) && (cmp(preNode->data, tempData) > 0))
            {   
                // 满足条件时,当前节点后移,直到不能后移时,就是新节点的位置了
                memcpy((preNode->next)->data, preNode->data, nodeDataSize);
                posNode = preNode;
                preNode = preNode->pre;
            }
            // 已经确定新节点的插入位置
            memcpy(posNode->data, tempData, nodeDataSize);
        }
        return 0;
    }
    

    六、测试

    // 链表的打印函数  
    static int printfDoubleList(char *info, DOUBLE_LINKED_NODE *node)
    {
        DOUBLE_LINKED_NODE *nodeTenp = node;
        printf("%s", info);
        while (nodeTenp != NULL && nodeTenp->data != NULL) {
            printf("%d ", *(int*)(nodeTenp->data));
            nodeTenp = nodeTenp->next;
        }
        printf("
    ");
        return 0;
    }
    
    // 测试代码
    int main(void)
    {
        int array[ARRAY_LEN] = {9, 3, 2, 4, 6, 7, 1, 0, 5, 8};
        char array_char[ARRAY_LEN] = {'a', 'h', 'd', 's', 'c', 'W', 'l', 'M', 'Z', 'z'};
        int ret;
        // ret = insertionSortV1(array, ARRAY_LEN, sizeof(int), intGreater);
        ret = insertionSortV2(array_char, ARRAY_LEN, sizeof(char), charGreater);
        if (ret != 0) {
            printf(" insetion sort array failed.ret=%d
    ", ret);
            goto out;
        }
        for (int i = 0; i < ARRAY_LEN; i++) {
            // printf("array[%d] = %d
    ", i, array[i]);
            printf("array_char[%d] = %c
    ", i, array_char[i]);
        }
    
        // 链表的测试函数:需要添加链表的创建和删除的函数实现,以及链表结构体定义
        int array[LIST_LEN] = {0, 5, 9, 2, 4, 1, 7, 6};
        DOUBLE_LINKED_NODE *temp;
        // 创建双链表
        temp = createDoubleLinkedList(array, LIST_LEN, sizeof(int));
        printfDoubleList("createList:", temp);
        // 插入排序
        insertionSortV3(temp, sizeof(int), intGreater);
        printfDoubleList("sortList:", temp);
        // 清空双链表
        clearDoubleLinkedList(temp);
        printfDoubleList("clearList.", temp);
    
    out:
        while (1);
        return 0;
    }
    

  • 相关阅读:
    Java数据结构之栈(Stack)
    Java数据结构之单向环形链表(解决Josephu约瑟夫环问题)
    Java数据结构之双向链表
    zookeeper:JavaApi操作节点
    zookeeper:3
    单例模式
    zookeeper:2
    架构版本
    zookeeper:1
    Java反射
  • 原文地址:https://www.cnblogs.com/HZL2017/p/14300857.html
Copyright © 2020-2023  润新知