• C语言实现链表


    以下是完整实现(配合教材使用更佳,教材见文章的标签):

    list.h

    typedef int ElementType;
    
    /* START: fig3_6.txt */
    #ifndef _List_H
    #define _List_H
    
    struct Node; // 使用结构体构造了节点
    typedef struct Node * PtrToNode; // 指向节点的指针
    typedef PtrToNode List; // 也是指向节点的指针
    typedef PtrToNode Position; // 指向任意节点的指针
    
    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 Advance( Position P );
    ElementType Retrieve( Position P );
    
    // 加一个打印的表的方法
    void PrintList(List L);
    
    #endif    /* _List_H */
    /* END */
    

    fatal.h

    #include <stdio.h>
    #include <stdlib.h>
    
    #define Error( Str )        FatalError( Str )
    #define FatalError( Str )   fprintf( stderr, "%s
    ", Str ), exit( 1 )
    

    main函数(对应书中的list.c)

    #include "list.h"
    #include <stdio.h>
    #include <stdlib.h>
    #include "fatal.h"
    
    /* Place in the interface file */
    struct Node
    {
        ElementType Element;
        Position Next;
    };
    
    List MakeEmpty(List L)
    {
        if (L != NULL)
            DeleteList(L); // 删除整个表
        L = malloc(sizeof(struct Node));
        if (L == NULL)
            FatalError("Out of memory!");
        L->Next = NULL;
        return L;
    }
    
    /* START: fig3_8.txt */
    /* Return true if L is empty */
    // 判断链表是否为空
    int IsEmpty(List L)
    {
        return L->Next == NULL;
    }
    /* END */
    
    /* START: fig3_9.txt */
    /* Return true if P is the last position in list L */
    /* Parameter L is unused in this implementation */
    // 判断是否是链表的最后一个元素
    int IsLast(Position P, List L)
    {
        return P->Next == NULL;
    }
    /* END */
    
    /* START: fig3_10.txt */
    /* Return Position of X in L; NULL if not found */
    // 返回某个元素在链表中的位置,如果不存在则返回NULL
    Position Find(ElementType X, List L)
    {
        Position P;
    
    /* 1*/      P = L->Next;
    /* 2*/      while (P != NULL && P->Element != X)
    /* 3*/          P = P->Next;
    
    /* 4*/      return P;
    }
    /* END */
    
    /* START: fig3_11.txt */
    /* Delete from a list */
    /* Cell pointed to by P->Next is wiped out */
    /* Assume that the position is legal */
    /* Assume use of a header node */
    // 删除表L中的某个元素X,如果X出现不止一次,我们就只是删除第一次出现的那一个,如果没有,我们就什么也不做
    void Delete(ElementType X, List L)
    {
        Position P, TmpCell;
    
        P = FindPrevious(X, L); // 找出X的前驱元
    
        if (!IsLast(P, L))  /* Assumption of header use */ // 这里的意思应该是使用了头节点,也就是说,删除第一个节点也是可以的,在头节点的帮助下
        {                      /* X is found; delete it */
            TmpCell = P->Next;
            P->Next = TmpCell->Next;  /* Bypass deleted cell */
            free(TmpCell);
        }
    }
    /* END */
    
    /* START: fig3_12.txt */
    /* If X is not found, then Next field of returned value is NULL */
    /* Assumes a header */
    
    Position FindPrevious(ElementType X, List L)
    {
        Position P;
    
    /* 1*/      P = L; // 从这里可以推断出,L指向的是表的第一个元素前面的头节点
        // 如果X没有找到,那么P就会是最后一个节点
    /* 2*/      while (P->Next != NULL && P->Next->Element != X)
    /* 3*/          P = P->Next;
    
    /* 4*/      return P;
    }
    /* END */
    
    /* START: fig3_13.txt */
    /* Insert (after legal position P) */
    /* Header implementation assumed */
    /* Parameter L is unused in this implementation */
    
    void Insert(ElementType X, List L, Position P)
    {
        Position TmpCell;
    
    /* 1*/      TmpCell = malloc(sizeof(struct Node));
    /* 2*/      if (TmpCell == NULL)
    /* 3*/          FatalError("Out of space!!!");
    
    /* 4*/      TmpCell->Element = X;
    /* 5*/      TmpCell->Next = P->Next;
    /* 6*/      P->Next = TmpCell;
    }
    /* END */
    
    // 当屏蔽掉大块代码时,使用"#if 0"比使用"/**/"要好,
    // 因为用"/**/"做大段的注释要防止被注释掉的代码中有嵌套的"/**/",
    // 这会导致注释掉的代码区域不是你想要的范围,
    // 当被注释掉的代码很大时容易出现这种情况,
    // 特别是过一段时间后又修改该处代码时更是如此。
    #if 0
    /* START: fig3_14.txt */
            /* Incorrect DeleteList algorithm */
    
            void
            DeleteList( List L )
            {
                Position P;
    
    /* 1*/      P = L->Next;  /* Header assumed */
    /* 2*/      L->Next = NULL;
    /* 3*/      while( P != NULL )
                {
    /* 4*/          free( P );
    /* 5*/          P = P->Next;
                }
            }
    /* END */
    #endif
    
    /* START: fig3_15.txt */
    /* Correct DeleteList algorithm */
    
    void DeleteList(List L)
    {
        Position P, Tmp;
    
    /* 1*/      P = L->Next;  /* Header assumed */
    /* 2*/      L->Next = NULL;
    /* 3*/      while (P != NULL) {
    /* 4*/          Tmp = P->Next;
    /* 5*/          free(P);
    /* 6*/          P = Tmp;
        }
    }
    
    /* END */
    // 头节点
    Position Header(List L)
    {
        return L;
    }
    
    Position First(List L)
    {
        return L->Next;
    }
    
    Position Advance(Position P)
    {
        return P->Next;
    }
    
    // 取回,取出结构体中的数值
    ElementType Retrieve(Position P)
    {
        return P->Element;
    }
    
    void PrintList(List L)
    {
        PtrToNode CopyL = L; // 复制一个L,这样往后遍历的时候就不会使L本身被修改
        if (CopyL->Next == NULL) {
            printf("当前链表为NULL! 
    ");
            return;
        }
        printf("开始打印链表:
    ");
        while (CopyL->Next != NULL) {
            CopyL = CopyL->Next;
            printf("%d
    ", CopyL->Element);
        }
        printf("打印结束!");
    }
    
    // 测试
    int main()
    {
        // 初始化表
        List L = (List) malloc(sizeof(struct Node));
        L->Element = -1;
        L->Next = NULL;
    
        // 测试打印空表
        PrintList(L);
        fflush(stdout);
    
        // 往链表中添加数据,从开头插入
        Insert(11, L, L);
        Insert(22, L, L);
        Insert(33, L, L);
        Insert(44, L, L);
        // 打印链表
        PrintList(L);
    
        // 从中间插入数据
        PtrToNode InsertAfter33 = L->Next->Next; // 把33这个位置给取出来
        Insert(31, L, InsertAfter33);
        // 打印链表
        PrintList(L);
    
        // 删除31这个元素
        Delete(31, L);
        // 打印链表
        PrintList(L);
    
        // 查找22这个数的位置
        Position position = Find(22, L);
        printf("查找到的值为:%d", position->Element);
    
    }
    

    测试结果:

    注:这是第3章 表、栈和队列的笔记

  • 相关阅读:
    线上问题随笔记录数据库连接池问题
    MySQL索引类型总结和使用技巧以及注意事项
    elastic-job的原理简介和使用
    新生 & 语不惊人死不休 —— 《无限恐怖》读后有感
    USACO Section2.1 Hamming Codes 解题报告 【icedream61】
    USACO Section2.1 Healthy Holsteins 解题报告 【icedream61】
    USACO Section2.1 Sorting a Three-Valued Sequence 解题报告
    USACO Section2.1 Ordered Fractions 解题报告
    USACO Section2.1 The Castle 解题报告
    USACO Section1.5 Superprime Rib 解题报告
  • 原文地址:https://www.cnblogs.com/fanlumaster/p/13659499.html
Copyright © 2020-2023  润新知