32.链表的的实现

时间:2021-08-25
本文章向大家介绍32.链表的的实现,主要包括32.链表的的实现使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

开发步骤:

  1. 建立抽象 自然语言描述

  2. 建立接口 list.h 编写类型的定义、结构体的定义、宏的定义、函数声明、include等内容

  3. 实现接口 list.c 编写函数的实现

  4. 使用接口 main.c list的使用

      5. 编译过程

               编译环境 : unix 、linux

     方法 1 :gcc main.c list.c 生成的可执行文件为a.out

               方法 2 :  gcc -o main main.c list.c ;./main 生成指定名称的可执行文件main

               注意事项 : 三个文件要放在同一文件夹内编译

1. list.h

/* list.h -- 简单链表类型的头文件 */
#ifndef LIST_H_
#define LIST_H_
#include <stdbool.h> /* C99 特性  */

/* 特定程序说明 */

#define TSIZE    45 /* 存储电影名称的数组大小 */
struct film
{
    char title[TSIZE];
    int rating;
};

/*    一般类型定义    */

typedef struct film Item;

typedef struct node
{
    Item item;
    struct node * next;
} Node;

typedef Node * List;

/*    函数原型    */

/*
操作:    初始化一个链表
前提条件:        plist指向一个一个链表
后置条件:        链表初始化为空
*/
void InitializeList(List * plist);

/*
操作:    确定链表是否为空定义,plist指向一个已经初始化的链表
前提条件:    
后置条件:        如果链表为空, 该函数返回true,否则返回false
*/
bool ListIsEmpty(const List *plist);

/*
操作:    确定链表是否已满,plist指向一个已初始化的链表
前提条件:    
后置条件:        如果链表已满,该函数返回true,否则返回false
*/
bool ListIsFull(const List *plist);

/*
操作:    确定链表中的项数,plist指向一个已初始化的链表
前提条件:
后置条件:        该函数返回链表中的项数
*/
unsigned int ListItemCount(const List *plist);

/*
操作:    为链表的末尾添加项
前提条件:        item是一个待添加至链表的项,plist指向一个已初始化的链表
后置条件:        如果可以(链表未满),该函数在链表末尾添加一个项,且返回true;否则返回false
*/
bool AddItem(Item item, List * plist);

/*
操作:    把函数作用与链表中每一项
前提条件:        plist指向一个已初始化的链表
            pfun指向一个函数,该函数接收一个item类型的参数,且无返回值
后置条件:        pfun指向的函数作用于链表中每一项一次
*/
void Traverse(const List *plist, void (*pfun)(Item item));

/*
操作:    释放已分配的内存(如果有的话)
前提条件:        plist指向一个已初始化的链表
后置条件:        释放了为链表分配的所有内存,链表设置为空
*/
void EmptyTheList(List * plist);

#endif

2. list.c

/*    list.c -- 支持链表操作的函数    */
#include <stdio.h>
#include <stdlib.h>
#include "list.h"

/* 局部函数原型    */
static void CopyToNode(Item item, Node * pnode);

//void show();

/* 接口函数    */

/*    把链表设置为空    */
void InitializeList(List * plist)
{
    *plist = NULL;
}

/*    如果链表为空,返回true    */
bool ListIsEmpty(const List *plist)
{
    if (*plist == NULL)
        return true;
    else
        return false;
}

/*    如果链表已满,返回true*/
bool ListIsFull(const List *plist)
{
    Node * pt;
    bool full;
    pt = (Node *)malloc(sizeof(Node));
    if (pt == NULL)
        full = true;
    else
        full = false;
    free(pt);

    return full;
}

/*    返回节点数量    */
unsigned int ListItemCount(const List *plist)
{
    unsigned int count = 0;
    Node * pnode = *plist; /*    设置链表的开始*/

    while (pnode != NULL)
    {
        ++count;
        pnode = pnode->next; /*    设置下一个节点*/
    }
    return count;
}

/*    创建储存项的节点,并将其添加至由plist指向的链表末尾(较慢的事项)*/
bool AddItem(Item item, List * plist)
{
    Node * pnew;
    Node * scan = *plist;

    pnew = (Node *) malloc(sizeof(Node));
    if (pnew == NULL)
        return false; /*    失败时退出函数*/
    
    CopyToNode(item, pnew);

    pnew->next = NULL;
    if (scan == NULL)
    {
        *plist = pnew; /* 空链pnew表,所有把 pnew放在链表的开头*/
    }
    else
    {
        while (scan->next != NULL)
            scan = scan->next; /*    找到链表的末尾*/
        scan->next = ; /*    把pnew添加到链表的末尾*/
    }
    printf("添加节点成功,title:%s  ,rating:%d   ,pt:%p\n", item.title, item.rating, &item );
    return true;
}


/*    访问每个节点并执行pfun指向的函数*/
void Traverse(const List *plist, void (*pfun)(Item item))
{
    Node * pnode = *plist; /*    设置链表的开始*/
    while (pnode != NULL)
    {
        (*pfun)(pnode->item); /*    把函数应用于链表中的项*/
        pnode = pnode->next; /*    前进到下一项*/
    }

}

/*    释放由malloc()分配的内存*/
/*    设置链表指针为NULL*/
void EmptyTheList(List * plist)
{
    Node * psave;
    while (*plist != NULL)
    {
        psave = (*plist)->next;    /*    保存下一个节点的地址*/
        free(*plist);    /* 释放当前节点*/
        *plist = psave;    /*    前进至下一个节点*/
    }
    puts("当前链表已清空");

}

/*    局部函数定义    */
/*    把一个项拷贝到节点中    */
static void CopyToNode(Item item,    Node * pnode)
{
    pnode->item =item; /* 拷贝结构*/
}

3. main.c

#include <stdio.h>
#include <stdlib.h> /*    提供exit()的原型*/
#include <string.h> /*    提供strchr()原型*/
//#include "list.c"
#include "list.h" /*    定义List、Item*/
void echo(Item temp);

void testList();
void testList2();

char * s_gets(char *st, int n);

int main(int argc, char const *argv[])
{
    //测试接口1
    //testList();

    //测试接口2
    testList();

    return 0;
}

/* 接收键盘录入字符串,并清除缓冲区*/
char * s_gets(char *st, int n)
{
    char * ret_val;
    char * find;
    
    ret_val = fgets(st, n, stdin); /* 将键盘录入内容存储到st(字符数组),当录入查过函数指定字节时,多余的部分会存储在缓冲区内*/
    //处理st中的\n和清空缓冲区
    if (ret_val) /* 所有不为0和NULL的值都为 true*/
    {
        find = strchr(st, '\n'); /* 判断指定字符串是否含有指定字符,有则返回该字符的指针,没有返回NULL*/
        if (find) /*    当指针不为NULL时,也就是包含\n时*/
            *find = '\0'; /* 将\n修改为\0*/ 
        else
            while (getchar() != '\n') /*    清空缓冲区*/
                continue;

    }
    return ret_val;

}

//打印方法的实现
void echo(Item temp)
{
    printf("title:%s  rating:%d  pt:%p\n", temp.title, temp.rating, &temp);    
}

//测试链表的方法1
void testList()
{
    //创建链表 Node *
    List movies;
    //创建项
    Item i1;
    //为项赋值
    i1.title[0] = 'g';
    i1.title[1] = 'a';
    i1.title[2] = 'o';
    i1.title[3] = 'c';
    i1.title[4] = 'u';
    i1.title[5] = 'n';
    i1.title[6] = '\0';
    i1.rating = 99;
    //初始化链表
    InitializeList(&movies);
    //为链表添加节点
    AddItem(i1,&movies);
    //当前节点数量
    unsigned int size = ListItemCount(&movies);
    printf("当前链表的节点数:%d\n", size );

    Item i2 = i1;
    i2.rating = 98;
    //为链表添加节点2
    AddItem(i2,&movies);
    printf("当前链表的节点数:%d\n", ListItemCount(&movies) );

    Item i3 = i1;
    i3.rating = 97;
    //为链表添加节点2
    AddItem(i3,&movies);
    printf("当前链表的节点数:%d\n", ListItemCount(&movies) );

    //遍历链表
    puts("开始遍历链表======");
    Traverse(&movies,echo);

    //清空链表
    EmptyTheList(&movies);

    //判断链表是否为空
    bool isRmpty = ListIsEmpty(&movies);
    printf("当前链表是否为空 : %d\n", isRmpty );

    //判断链表是否为满
    bool isFull = ListIsFull(&movies);
    printf("当前链表是否为满 : %d\n", isFull );

    echo(i1);
    echo(i2);
    echo(i3);

}

void testList2()
{
    List movies;    
    Item temp;

    /*    初始化 */
    InitializeList(&movies);
    /*    确定是否有内存可用*/
    if ( ListIsFull(&movies))
    {
        fprintf(stderr, "No memory avaliable! Bye!\n" );
        exit(1);
    }
    // /*    获取用户输入并存储*/
    // puts("Enter first movie titile:");
    while (s_gets(temp.title, TSIZE) != NULL && temp.title[0] != '\0')
    {
        puts("Enter your rating <0-10>:");
        scanf("%d",&temp.rating);
        //清空缓冲区
        while (getchar() != '\n')
            continue;
        if (AddItem(temp, &movies) == false)
        {
             fprintf(stderr, "Problem allocating memory\n" );
             break;
        }
        //判断链表是否满
        if (ListIsFull(&movies))
        {
            puts("The list is now full.");
            break;
        }
        puts("Enter next movie title (empty line to stop)");
    }

    /*    遍历链表*/
    if (ListIsEmpty(&movies))
        printf("No data entered.\n" );
    else
    {
        printf("Here is the movie list:\n" );
        Traverse(&movies,echo);
    }
    printf("You entered %d movies.\n", ListItemCount(&movies));

    /* 是否内存*/
    EmptyTheList(&movies);
    printf("Bye!\n" );

}

原文地址:https://www.cnblogs.com/bajiaotai/p/15184244.html