渐增型算法一:插入排序

一、算法说明

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("\n");
    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\n", ret);
        goto out;
    }
    for (int i = 0; i < ARRAY_LEN; i++) {
        // printf("array[%d] = %d\n", i, array[i]);
        printf("array_char[%d] = %c\n", 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;
}

posted @ 2021-01-20 01:26  Pangolin2  阅读(105)  评论(0编辑  收藏  举报