风也温柔

计算机科学知识库

链表的基本操作c语言版数据结构-c语言实现单链表数据结构及其基本操作

  带头结点单链表。分三个文件链表的基本操作c语言版数据结构,分别为头文件,测试文件,源代码文件。

  给出了单链表的部分操作链表的基本操作c语言版数据结构链表的基本操作c语言版数据结构-c语言实现单链表数据结构及其基本操作,每个操作都有对应的注释说明该函数功能。

  test.c 文件中,对输入数据是否合法进行了检测,但是并未实现输入数据不合法时应该采取的措施。

  测试文件 通过一个菜单来测试单链表功能。

  c语言基本类型数据_链表的基本操作c语言版数据结构_顺序链表c语言版

  list.h:

   / 单链表类型的头文件 /

    #ifndef LIST_H_
    #define LIST_H_ 
    struct Node;                                    //先声明,就可以在下面使用,而不必因定义在后面而产生冲突
     
    /*  一般类型定义  */  
    typedef int ElementType;                        //抽象数据类型  
    typedef struct Node * PtrToNode;
    typedef PtrToNode List;
    typedef PtrToNode Position;
    /*  特定于程序的声明  */   
    struct Node {
        ElementType element;  
        Position    next;
    };
    /*  函数原型  */  
    List MakeEmpty ( List l );
    int IsEmpty ( List L );
    int IsLast ( Position p, List l );
    Position Find ( ElementType x, List l );
    void Delete ( ElementType x, List l );
    Position FindPrevious ( ElementType x, List l );
    void Insert ( ElementType x, List l, Position p );
    void DeleteList ( List l );
    Position Header ( List l );
    Position First ( List l );
    Position Last ( List l );
    Position Advance ( Position p );
    ElementType Retrieve ( Position p );
    void PushFront ( ElementType x, List l );
    void PopFront ( List l );
    void PushBack ( ElementType x, List l );
    void PopBack ( List l );

  test.c:

   / 单链表 /

    #include   
    #include   
    #include "list.h"
    struct Node;
    void Menu ( void );                                //菜单  
    void PrintList ( List l );                        //打印单链表
    int main ( void )  
    {  
        List l;
        int choice;  
        ElementType x;  
        l = NULL;
        choice = 0;
        x = 0;
      
        Menu (  );
      
        scanf ( "%d", &choice );  
      
        while ( 0 != choice )  
        {  
            switch ( choice )  
            {  
            case 1: if ( NULL == ( l = MakeEmpty ( l ) ) )    //如若不接受返回值,则外面 l 未改变。因为 MakeEmpty 中形参 不影响 实参值,开辟的空间反而找不到了!重点!!
                    {
                    printf ( "初始化失败!\n" );
                    }
                    else
                    {
                        printf ( "初始化成功!\n" );
                    }
                    break;  
            case 2: if ( 1 == IsEmpty ( l ) )
                    {
                        printf ( "单链表为空!\n" );
                    }
                    else
                    {
                        printf ( "单链表不为空!\n" );
                    }
                    break;  
            case 3: {
                        Position p;
                        p = Last ( l );
                        if ( NULL == p )
                        {
                            printf ( "0.链表中没有结点,当前位置是链表末尾!\n" );
                            break;
                        }
                        if ( 1 == IsLast ( p , l ) )
                        {
                            printf ( "1.当前位置是链表末尾!\n" );
                        }
                        if ( 0 == IsLast ( l, l ) )
                        {
                            printf ( "2.当前位置不是链表末尾!\n" );
                        }
      
                      break;  
                    }
            case 4:    printf ( "请输入需要查找的元素: " );
                    if ( 1 == scanf ( "%d", &x ) )
                    {
                        Position tmp;
                        tmp = Find ( x ,l );
                        if ( NULL == tmp )
                        {
                            printf ( "元素%d不存在!\n", x );
                        }
                        else
                        {
                            printf ( "找到了元素%d!\n", ( Retrieve ( tmp ) ) );
                        }
                    }
                    else
                    {
                        printf ( "输入数据不合法,查找失败!\n" );
                    }
                    break;
            case 5: printf ( "请输入需要删除的元素: " );
                    if ( 1 == scanf ( "%d", &x ) )
                    {
                        Delete ( x, l );
                        printf ( "删除成功!\n" );
                    }
                    else
                    {
                        printf ( "输入数据不合法,删除失败!\n" );
                    }
                    break;
            case 6: printf ( "请输入需要插入的元素: " );//此处实现为头插
                    if ( 1 == scanf ( "%d", &x ) )
                    {
                        Insert ( x, l, l );
                        printf ( "插入成功!\n" );
                    }
                    else
                    {
                        printf ( "输入数据不合法,插入失败!\n" );
                    }
                    break;  
            case 7: DeleteList ( l );
                    printf ( "删除单链表成功!\n" );
                    l = NULL;
                    break;
            case 8: printf ( "请输入需要插入的元素: " );
                    if ( 1 == scanf ( "%d", &x ) )
                    {
                        PushFront ( x, l );
                        printf ( "插入成功!\n" );
                    }
                    else
                    {
                        printf ( "输入数据不合法,插入失败!\n" );
                    }
                    break;  
            case 9: PopFront ( l );
                
                    printf ( "删除成功!\n" );
                    break;  
            case 10: printf ( "请输入需要插入的元素: " );
                     if ( 1 == scanf ( "%d", &x ) )
                     {
                         PushBack ( x, l );
                          printf ( "插入成功!\n" );
                     }
                     else
                     {
                         printf ( "输入数据不合法,插入失败!\n" );
                      }
                     break;  
            case 11: PopBack ( l );
                     printf ( "删除成功!\n" );
                     break;  
            case 12: PrintList ( l );
                     break;
            default: printf ( "放弃吧!\n" );   
                       
                     break;  
            }     
      
            Menu ( );  
            scanf ( "%d", &choice );  
        }  
      
        system ( "pause" );  
      
        return 0;  
      
    }  
      
      
    void Menu ( void )                              //菜单  
    {  
        printf ( "***************************************************************\n" );  
        printf ( "  1.初始化                    2.是否为空\n" );  
        printf ( "  3.当前位置是否是链表末尾            4.查找元素\n" );  
        printf ( "  5.删除元素                    6.插入元素\n" );  
        printf ( "  7.删除链表                    8.头插数据\n" );  
        printf ( "  9.头删数据                    10.尾插数据\n" );  
        printf ( "  11.尾删数据                    12.打印\n" );  
        printf ( "***************************************************************\n" );  
    }  
      
    void PrintList ( List l )                        //打印单链表
    {  
        Position p;
        p = l -> next;
        while ( NULL != p )
        {
            printf ( "%d -> ", ( p -> element ) );
            p = p -> next;
        }
        printf ( "\n" );
    }  
      

  list.c:

   / list.c -- 支持单链表操作的函数 /

    #include   
    #include 
    #include "list.h"  
    /*  接口函数  */  
    /*  把单链表初始化为空单链表  */                //必须先初始化再使用链表(未初始化链表下列函数可能出错.)
    List MakeEmpty ( List l )                        //传进来的 l 是一个指向单链表这种数据结构的指针,但不一定已经开辟了这种结构的空间使指针去指向
    {
        if ( NULL != l )                            //结合 收藏夹 -> c语言,  理解为什么将指针free( )后需置NULL
        {
            DeleteList ( l );
        }
        l = ( List )malloc ( sizeof ( struct Node ) );//malloc 完一定要检查是否 开辟空间成功!
        if ( NULL == l )
        {
            printf ( "开辟空间失败!" );
            return NULL;
        }
        l -> element = 0;
        l -> next = NULL;
        return l;
    }
    /*  检查单链表是否为空  */  
    int IsEmpty ( List l )  
    {  
        return ( NULL == l -> next );
    }  
     
    /*  检查当前位置是否是链表的末尾  */            //将只有头结点情况视为链表末尾
    int IsLast ( Position p, List l )
    {
        return ( NULL == p -> next );
    }
    /*  在单链表中查找元素x  */
    Position Find ( ElementType x, List l )
    {
        Position p;
        p = l -> next;                                //声明和定义分开.
        while ( ( NULL != p ) && ( x != p -> element ) )
        {
            p = p -> next;
        }
        return p;
    }
    /*  在单链表中删除元素x  */                        //元素不存在,函数不做任何处理
    void Delete ( ElementType x, List l )            //使用到了 FindPrevious( )函数
    {
        Position p;
        Position tmpCell;
        
        p = FindPrevious ( x, l );
        if ( !( IsLast ( p, l ) ) )
        {
            tmpCell = p -> next;
            p -> next = p -> next -> next;            //注意!是赋值给p的next域,而不是p!    
            free ( tmpCell );                        //free( )掉指针后,最好将指针置NULL.
            tmpCell = NULL;
        }
    }
    /*  在单链表中找出元素x的前驱位置  */            //辅助Find函数实现,不提供测试代码(若Find函数执行成功,则此函数正确)
    Position FindPrevious ( ElementType x, List l )
    {
        Position p;
        p = l;                                        //在外面申请头节点,所以l不可能为空
        while ( ( NULL != p -> next ) && ( x != p -> next -> element ) )
        {
            p = p -> next;
        }
        return p;                                    //返回的不是next域!也永远不可能是!
    }
    /*  在单链表中插入元素x  */
    /*  插入到当前位置的后面  */
    void Insert ( ElementType x, List l, Position p )
    {
        Position tmpCell;                            //只是创建了一个指针,还需要malloc出结构体的大小.5.
        tmpCell = ( List )malloc ( sizeof ( struct Node ) );//struct Node 只是一个类型, sizeof( sturct Node )才是它的大小. 才能使用malloc.
        if ( NULL == tmpCell )                        //因为系统资源问题,所以malloc申请空间可能会失败,养成malloc后检查申请是否成功的习惯6.
        {
            printf ( "申请空间失败" );
        }
        else
        {
        tmpCell -> element = x;
        tmpCell -> next = p -> next;
        p -> next = tmpCell;
        }
    }
    /*  删除单链表  */
    void DeleteList ( List l )                        //删除单链表后再使用单链表必须先初始化.
    {
        Position p;
        Position tmp;
        p = l -> next;                                //l 的next 域存放地址给p  free l 后,这个p所保存地址依然在和 l 无关。 lnext域只是之前用来保存它
        free ( l );                                    //此处通过指针l释放l指向的头结点,而不是释放指针l,指针l依然存在.
        l = NULL;                                    //记得,你在此处改变l的值,外面l值依旧没改变。   所以,这种错误不要再犯了!  
        while ( NULL != p )
        {
            tmp = p -> next;    
            free ( p );                                //此处释放的是p,不是p的next域(不要释放下一个节点)
            p = tmp;
        }
    }
    /*  返回链表头结点  */                            //不提供测试用例
    Position Header ( List l )
    {
        return l;
    }
    /*  返回链表第一个结点  */                        //不提供测试用例
    Position First ( List l )
    {
        return ( l -> next );
    }
    /*  返回链表的最后一个结点  */                    //不提供测试用例
    Position Last ( List l )
    {
        Position p = l;
        if ( NULL == l -> next )                    //将头节点后那个结点视为第一个结点,所以只有头结点时,视为没有结点.
        {
            return NULL;
        }
        else
        {
            while ( NULL != p -> next )
            {
                p = p -> next;
            }
        }
        return p;
    }
    /*  返回位置p的下一个位置  */                    //不提供测试用例
    Position Advance ( Position p )
    {
        return ( p -> next ); 
    }
    /*  返回位置p处的元素  */                        //不提供测试用例
    ElementType Retrieve ( Position p )
    {
        return ( p -> element );
    }
    /*  在单链表头部插入元素x  */                    //版本1
    //void PushFront ( ElementType x, List l )        //使用到了 Header( )函数 与 Insert( )函数
    //{
    //    Insert ( x, l, Header ( l ) );
    //}
    /*  在单链表头部插入元素x  */                    //版本2
    void PushFront ( ElementType x, List l )
    {
        Position tmp;                                //不需要再定义一个多余的变量保存 l -> next.
        tmp = ( List )malloc ( sizeof ( struct Node ) );
        if ( NULL == tmp )
        {
            printf ( "申请空间失败,插入不成功!" );//抽象数据类型中别加多余东西( 换行符 ).
        }
        else
        {
            tmp -> element = x;
            tmp -> next = l -> next;
            l -> next = tmp;
        }
    }
    /*  删除单链表第一个结点  */
    void PopFront ( List l )        
    {
        if ( NULL == l -> next )
        {
            ;
        }
        else
        {
            Position tmp;
            tmp = l -> next;                        //注意此处释放 l的next域中值才是释放了第一个结点,而不是释放第一个结点next域(第二个结点).
            l -> next = tmp -> next;
            
            free ( tmp );                            //释放的next域只是下一个结点,不是这个结点,也不是释放了next.
            tmp = NULL;
        }
    }
    /*  在单链表尾部插入元素x  */
    void PushBack ( ElementType x, List l )            //使用 Header( )函数
    {
        Position p;
        Position tmp;
        p = Header ( l );
        while ( NULL != p -> next )
        {
            p = p -> next;
        }
        tmp = ( List )malloc ( sizeof ( struct Node ) );
        if ( NULL == tmp )
        {
            printf ( "申请空间失败,插入失败" );
        }
        else
        {
            tmp -> element = x;
            tmp -> next = NULL;
            p -> next = tmp;
        }
    }
    /*  删除单链表最后一个结点  */
    void PopBack ( List l )
    {
        if ( NULL == l -> next )
        {
            ;
        }
        else
        {
            Position p;
            p = l;
            while ( NULL != p -> next -> next  )
            {
                p = p -> next;
            }
            free ( p -> next );
            p -> next = NULL;
        }

  文章来源:https://blog.csdn.net/ssopp24/article/details/60322963