C数据结构-线性表之单链表

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/water_3700348/article/details/78135659

线性表之单链表

单链表的设计之初,笔者在考虑一个首要的问题,就是单链表的节点是在插入的函数内部创建,还是在函数外部创建。考虑到用户在插入的时候,变量生命周期的不确定性以及容易造成内存泄漏等问题,综合考虑之下使用了内部创建节点的方式。笔者设计的单链表中包含了单链表的反转和合并等有趣的操作,其中的奥妙如果读者有兴趣可以细究。比如为什么笔者使用了二级指针来合并单链表,而不直接使用一级指针,比如为什么在清空链表节点时,根据length清空会有可能会发生内存泄漏....等等。下面是代码:

#ifndef LINKEDLIST_H
#define LINKEDLIST_H

#ifndef NULL
#define NULL 0
#endif

/* 元素类型 */
typedef int elem_t;

/* 节点结构体 */
typedef struct _tag_linked_list_node
{
    elem_t data;
    struct _tag_linked_list_node *next;
}ll_node;

/* 链表结构体 */
typedef struct _tag_linked_list
{
    ll_node head;   /* 哑结点 */
    int length;     /* 链表长度 */
}linked_list;

/**
 * 创建链表
 * @return  返回链表指针,NULL表示创建失败
 */
linked_list *linked_list_create();

/**
 * 从头部插入元素
 * @param plist 链表指针
 * @param pe    被插入元素的指针
 * @return      1:成功 0:失败
 */
int linked_list_insert(linked_list *plist,elem_t *pe);

/**
 * 从尾部插入元素
 * @param plist 链表指针
 * @param pe    被插入元素的指针
 * @return      1:成功 0:失败
 */
int linked_list_append(linked_list *plist,elem_t *pe);

/**
 * 查找元素
 * @param plist 链表指针
 * @param i     元素位置索引
 * @param pe    用于保存被查找元素的值的指针
 * @return      1:成功 0:失败
 */
int linked_list_get(linked_list *plist,int i,elem_t *pe);


/**
 * 按索引删除元素
 * @param plist 链表指针
 * @param i     被删除元素的索引
 * @param pe    用于保存被删除元素的值的指针
 * @return      1:成功 0:失败
 */
int linked_list_remove(linked_list *plist,int i,elem_t *pe);

/**
 * 链表反转
 * @param plist 链表指针
 * @return 1:成功 0:失败
 */
int linked_list_reverse(linked_list *plist);

/**
 * 链表合并,将第二个链表链接到第一个链表,第二个链表指针置空
 * @param dest 合并的目标链表
 * @param pp_src 被合并的链表的指针的指针
 * @return 返回合并后的链表的指针(第一个参数)
 */
linked_list *linked_list_merge(linked_list *dest,linked_list **pp_src);


/**
 * 清空链表
 * @param plist 链表指针
 * @return      1:成功 0:失败
 */
int linked_list_clear(linked_list *plist);

/**
 * 销毁链表
 * @param plist 链表指针
 * @return      1:成功 0:失败
 */
int linked_list_destroy(linked_list *plist);




#endif // LINKEDLIST_H


#include "LinkedList.h"
#include <malloc.h>

/**
 * 创建链表
 * @return  返回链表指针,NULL表示创建失败
 */
linked_list *linked_list_create()
{
    linked_list *plist = (linked_list *)malloc(sizeof(linked_list));

    if(plist != NULL)
    {
        plist->length = 0;
        plist->head.next = NULL;
    }

    return plist;
}

/**
 * 从头部插入元素
 * @param plist 链表指针
 * @param pe    被插入元素的指针
 * @return      1:成功 0:失败
 */
int linked_list_insert(linked_list *plist,elem_t *pe)
{
    int ret = ( (plist != NULL) && (pe != NULL));

    if(ret)
    {
        ll_node *node = (ll_node *)malloc(sizeof(ll_node));
        ll_node *head = &(plist->head);
        if(node != NULL)
        {
            node->next = head->next;
            head->next = node;
            node->data = *pe;

            plist->length++;
        }
        else
        {
            ret = 0;
        }
    }

    return ret;
}

/**
 * 从尾部插入元素
 * @param plist 链表指针
 * @param pe    被插入元素的指针
 * @return      1:成功 0:失败
 */
int linked_list_append(linked_list *plist,elem_t *pe)
{
    int ret = ( (plist != NULL) && (pe != NULL));

    if(ret)
    {
        ll_node *node = (ll_node *)malloc(sizeof(ll_node));
        if(node != NULL)
        {
            int pos = 0;
            ll_node *current = &(plist->head);
            /* 移动到尾部 */
            for(pos = 0;pos < plist->length;pos++)
            {
                current = current->next;
            }
            node->next = NULL;
            node->data = *pe;
            current->next = node;

            plist->length++;
        }
        else
        {
            ret = 0;
        }
    }

    return ret;
}

/**
 * 查找元素
 * @param plist 链表指针
 * @param i     元素位置索引
 * @param pe    用于保存被查找元素的值的指针
 * @return      1:成功 0:失败
 */
int linked_list_get(linked_list *plist,int i,elem_t *pe)
{
    int ret = ( (plist != NULL) && (pe != NULL)  && (i >= 0) && (i < plist->length));

    if(ret)
    {
        int pos = 0;
        ll_node *current = plist->head.next;
        /* 移动到尾部 */
        for(pos = 0;pos < i;pos++)
        {
            current = current->next;
        }

        *pe = current->data;
    }

    return ret;
}

/**
 * 按索引删除元素
 * @param plist 链表指针
 * @param i     被删除元素的索引
 * @param pe    用于保存被删除元素的值的指针
 * @return      1:成功 0:失败
 */
int linked_list_remove(linked_list *plist,int i,elem_t *pe)
{
    int ret = ( (plist != NULL) && (pe != NULL) && (i >= 0) && (i < plist->length));

    if(ret)
    {
        int pos = 0;
        ll_node *pre = &(plist->head);

        for(pos = 0;pos < i;pos++)
        {
            pre = pre->next;
        }
        /* 保存要被删除的元素的值 */
        *pe = pre->next->data;

        pre->next = pre->next->next;

        plist->length--;
    }

    return ret;
}

/**
 * 链表反转
 * @param plist 链表指针
 * @return 1:成功 0:失败
 */
int linked_list_reverse(linked_list *plist)
{
    int ret = (plist != NULL);

    if(ret)
    {
        if(plist->length > 1)
        {
            int i;
            /* 保存尾元素的指针 */
            ll_node *tail = &(plist->head);
            for(i = 0;i < plist->length;i++)
            {
                tail = tail->next;
            }

            /* 将头元素的位置调整到原尾元素的后部插入 */
            while(plist->head.next != tail)
            {
                /* 保存头部元素的指针 */
                ll_node *old_head = plist->head.next;
                /* 调整头结点指针的位置,指向原头部的下一个元素 */
                plist->head.next = old_head->next;
                /* 将保存的原头部元素插入到原尾部元素的后面 */
                old_head->next = tail->next;
                tail->next = old_head;

            }
        }
    }

    return ret;
}

/**
 * 链表合并,将第二个链表链接到第一个链表,第二个链表指针置空
 * @param dest 合并的目标链表
 * @param pp_src 被合并的链表的指针的指针
 * @return 返回合并后的链表的指针(第一个参数)
 */
linked_list *linked_list_merge(linked_list *dest,linked_list **pp_src)
{
    if((dest != NULL) && ( (*pp_src) != NULL) && ((*pp_src)->length != 0))
    {
        int i;
        ll_node *current = &(dest->head);
        /* 移动到目标链表的尾部元素 */
        for(i = 0;i < dest->length;i++)
        {
            current = current->next;
        }

        current->next = (*pp_src)->head.next;
        dest->length += (*pp_src)->length;
        free(*pp_src);
        *pp_src = NULL;
    }

    return dest;
}

/**
 * 清空链表
 * @param plist 链表指针
 * @return      1:成功 0:失败
 */
int linked_list_clear(linked_list *plist)
{
    int ret = ((plist != NULL) && (plist->length != 0));

    if(ret)
    {
        /*
         * 这种清空的循环不妥,当外部恶意修改了plist->length,那么将会发生内存泄漏
        int i;
        for(i = 0;i < plist->length;i++)
        {
            ll_node *del = plist->head.next;
            plist->head.next = del->next;
            free(del);
        }
        */
        ll_node *head = &(plist->head);
        while(head->next != NULL)
        {
            ll_node *del = head->next;
            head->next = del->next;
            free(del);
        }
        plist->length = 0;
    }

    return ret;
}

/**
 * 销毁链表
 * @param plist 链表指针
 * @return      1:成功 0:失败
 */
int linked_list_destroy(linked_list *plist)
{
    int ret = (plist != NULL);

    if(ret)
    {
        linked_list_clear(plist);
        free(plist);
    }

    return ret;
}


猜你喜欢

转载自blog.csdn.net/water_3700348/article/details/78135659