数据结构与算法——实验一

链表

题目要求

实验题目:单链表的基本操作

实验目的:
了解和掌握线性表的逻辑结构和链式存储结构,掌握单链表的基本算法及相关的时间性能分析。

实验要求:
建立一个数据域定义为字符串的单链表,在链表中不允许有重复的字符串;根据输入的字符串,先找到相应的结点,后删除之。

实验主要步骤:
1、    分析、理解给出的示例程序。
2、    调试程序,并设计输入数据(如:bat,cat,eat,fat,hat,jat,lat,mat,#),测试程序的如下功能:不允许重复字符串的插入;根据输入的字符串,找到相应的结点并删除。
3、    修改程序:
(1)    增加插入结点的功能。
(2)    增加建立链表的尾插入法。

初始代码

#include"stdio.h"
#include"string.h"
#include"stdlib.h"
#include"ctype.h"
typedef struct node          //定义结点
{
    char data[10];             //结点的数据域为字符串
    struct node *next;      //结点的指针域
}ListNode;

typedef ListNode * LinkList;         // 自定义LinkList单链表类型
LinkList CreatListR1();              //函数,用尾插入法建立带头结点的单链表
LinkList CreatList();            //函数,用头插入法建立带头结点的单链表
ListNode *LocateNode();              //函数,按值查找结点
void DeleteList();                   //函数,删除指定值的结点
void printlist();                    //函数,打印链表中的所有值
void DeleteAll();                    //函数,删除所有结点,释放内存
ListNode * AddNode();                 //修改程序:增加节点。用头插法,返回头指针

//==========主函数==============

void main()
{
    char ch[10],num[5];
    LinkList head;
    head=CreatList();          //用头插入法建立单链表,返回头指针
    printlist(head);             //遍历链表输出其值
    printf(" Delete node (y/n):");  //输入"y"或"n"去选择是否删除结点
    scanf("%s",num);
    if(strcmp(num,"y")==0 || strcmp(num,"Y")==0){
        printf("Please input Delete_data:");
        scanf("%s",ch);            //输入要删除的字符串
        DeleteList(head,ch);
        printlist(head);
    }
    printf(" Add node ? (y/n):");  //输入"y"或"n"去选择是否增加结点
    scanf("%s",num);
    if(strcmp(num,"y")==0 || strcmp(num,"Y")==0)
    {
        head=AddNode(head);
    }

    printlist(head);
    DeleteAll(head);            //删除所有结点,释放内存
}
//==========用尾插入法建立带头结点的单链表===========
LinkList CreatListR1(void)
{
}

//==========用头插入法建立带头结点的单链表===========
LinkList CreatList(void)
{

    while(1)
    {
        printf("Input # to end  ");  
        printf("Please input Node_data:");
        scanf("%s",ch);         
        if(strcmp(ch,"#"))
        {     
            if(LocateNode(head,ch)==NULL) 
            {   
            }
        }
        else 
            break;
    }
    return head;      
}

//==========按值查找结点,找到则返回该结点的位置,否则返回NULL==========
ListNode *LocateNode(LinkList head, char *key)
{
}

//==========增加节点=======
ListNode * AddNode(LinkList head)
{
}

//==========删除带头结点的单链表中的指定结点=======
void DeleteList(LinkList head,char *key)
{
ListNode *p,*r,*q=head;
    p=LocateNode(head,key);    //按key值查找结点的
    if(p==NULL ) {            //若没有找到结点,退出
        printf("position error");
        exit(0);
    }
}
//===========打印链表=======
void printlist(LinkList head)
{
    ListNode *p=head->next;       //从开始结点打印
    while(p){
        printf("%s,   ",p->data);
        p=p->next;
    }
    printf("\n");
}
//==========删除所有结点,释放空间===========
void DeleteAll(LinkList head)
{
    ListNode *p=head,*r;
}

代码实现

#include"stdio.h"
#include"string.h"
#include"stdlib.h"
#include"ctype.h"
typedef struct node          //定义结点
{
    char data[10];             //结点的数据域为字符串
    struct node *next;      //结点的指针域
}ListNode;

typedef ListNode * LinkList;         // 自定义LinkList单链表类型
LinkList CreatListR1();              //函数,用尾插入法建立带头结点的单链表
LinkList CreatList();            //函数,用头插入法建立带头结点的单链表
ListNode *LocateNode();              //函数,按值查找结点
void DeleteList();                   //函数,删除指定值的结点
void printlist();                    //函数,打印链表中的所有值
void DeleteAll();                    //函数,删除所有结点,释放内存
ListNode * AddNode();                 //修改程序:增加节点。用头插法,返回头指针

//==========主函数==============

int main()
{
    char ch[10],num[5];
    LinkList head;
    head=CreatListR1();          //用头插入法建立单链表,返回头指针    这里可以切换尝试头插法和尾插法
    printlist(head);             //遍历链表输出其值
    printf(" Delete node (y/n):");  //输入"y"或"n"去选择是否删除结点
    scanf("%s",num);
    if(strcmp(num,"y")==0 || strcmp(num,"Y")==0){
        printf("Please input Delete_data:");
        scanf("%s",ch);            //输入要删除的字符串
        DeleteList(head,ch);
        printlist(head);
    }
    printf(" Add node ? (y/n):");  //输入"y"或"n"去选择是否增加结点
    scanf("%s",num);
    if(strcmp(num,"y")==0 || strcmp(num,"Y")==0)
    {
        head=AddNode(head);
        printlist(head);
    }
    DeleteAll(head);            //删除所有结点,释放内存
    return 1;
}

//==========用尾插入法建立带头结点的单链表===========
LinkList CreatListR1(void)
{
    LinkList head;
    head = (LinkList)malloc(sizeof(LinkList));
    head->next = NULL;
    ListNode *p, *q = head;    // 创建新增节点p和尾指针q
    while(1)
    {
        printf("Input # to end  ");  
        printf("Please input Node_data:");
        char ch[10];
        scanf("%s",ch);         
        if(strcmp(ch,"#"))
        {     
            if(LocateNode(head,ch)==NULL) 
            {
                p = (ListNode *)malloc(sizeof(ListNode));
                strcpy(p->data, ch);
                p->next = NULL; // 这一步真重要,之前一直卡在这里,若没赋空值,赋给p后,进入LocateNode判断会报错,因为q->next->next不是个地址同时也不为空!
                q->next = p;
                q = p;
                // p->next = NULL;
            }
        }
        else 
            break;
    }
    q->next = NULL;
    return head; 
}

//==========用头插入法建立带头结点的单链表===========
LinkList CreatList(void)
{
    LinkList head;
    head = (ListNode *)malloc(sizeof(ListNode));
    head->next = NULL;
    ListNode *p = NULL;
    while(1)
    {
        printf("Input # to end  ");  
        printf("Please input Node_data:");
        char ch[10];
        scanf("%s", ch);
        if(strcmp(ch,"#"))
        {     
            if(LocateNode(head,ch)==NULL) 
            {
                p = (ListNode *)malloc(sizeof(ListNode));
                strcpy(p->data, ch);
                p->next = head->next;
                head->next = p;
            }
            else
                printf("You have already input this Node_data!\n");
        }
        else
        {
            break;
        }
    }
    return head;      
}

//==========按值查找结点,找到则返回该结点的位置,否则返回NULL==========
ListNode *LocateNode(LinkList head, char *key)
{
    ListNode *p = head->next;
    while (p && strcmp(p->data,key))
    {
        p = p->next;
    }
    return p;
}

//==========增加节点=======
ListNode * AddNode(LinkList head)
{
    ListNode *p = head->next;
    printf("Please input Node_data:");
    char ch[10];
    scanf("%s", ch);
    if(LocateNode(head,ch)==NULL) 
    {
        p = (ListNode *)malloc(sizeof(ListNode));
        strcpy(p->data, ch);
        p->next = head->next;
        head->next = p;
    }
    else
        printf("You have already input this Node_data!\n");
    return head;
}

//==========删除带头结点的单链表中的指定结点=======
void DeleteList(LinkList head, char *key)
{
    ListNode *p = head, *q = NULL;
    while (p && strcmp(p->data,key))
    {
        q = p;
        p = p->next;
    }
    if (p != NULL)
    {
        q->next = p->next;
        free(p);
    }
    else
        printf("结点不存在\n");
}

//===========打印链表=======
void printlist(LinkList head)
{
    ListNode *p=head->next;       //从开始结点打印
    while (p) {
        printf("%s,   ",p->data);
        p=p->next;
    }
    printf("\n");
}

//==========删除所有结点,释放空间===========
void DeleteAll(LinkList head)
{
    ListNode *p;
    while (head)
    {
        p = head;
        head = head->next;
        free(p);
    }
    printf("All data has been deleted!");
}

代码分析

创建链表参考:C 语言学习回顾 - 404!v|+_+|v 404!

理解这些概念的最好方法是画个流程图

输入数据为bat,cat,eat,fat,hat,jat,lat,mat,#

头插法创建链表

//==========用头插入法建立带头结点的单链表===========
LinkList CreatList(void)
{
    LinkList head;    // 定义头指针
    head = (ListNode *)malloc(sizeof(ListNode));    // 为头指针分配内存空间
    head->next = NULL;    // 头指针的指向地址赋空值
    ListNode *p = NULL;    // 定义一个指针p来接收赋值和传递地址
    while(1)
    {
        printf("Input # to end  ");  
        printf("Please input Node_data:");
        char ch[10];
        scanf("%s", ch);    // 数组形式不用取地址符号&
        if(strcmp(ch,"#"))    // strcmp判断ch是否等于#,若等于则返回0,否则返回其他数
        {     
            if(LocateNode(head,ch)==NULL)    // 转到判断是否输入重复字符串
            {
                p = (ListNode *)malloc(sizeof(ListNode));    // 为p指针分配内存空间
                strcpy(p->data, ch);    // 这里因为ch为char类型,不能直接赋值,而应使用strcpy
                p->next = head->next;    // 将head的next指针指向p的下一节点
                head->next = p;            // head向后移
            }
            else
                printf("You have already input this Node_data!\n");    // 重复
        }
        else
        {
            break;
        }
    }
    return head;      
}

补充:

  • strcmp用法:image-20210916213143801.png
  • strcpy():用来将字符串的值赋给指针,直接使用=会报错
结果展示

image-20210922172912830.png

尾插法创建链表

//==========用尾插入法建立带头结点的单链表===========
LinkList CreatListR1(void)
{
    LinkList head;
    head = (LinkList)malloc(sizeof(LinkList));
    head->next = NULL;
    ListNode *p, *q = head;
    while(1)
    {
        printf("Input # to end  ");  
        printf("Please input Node_data:");
        char ch[10];
        scanf("%s",ch);         
        if(strcmp(ch,"#"))
        {     
            if(LocateNode(head,ch)==NULL) 
            {
                p = (ListNode *)malloc(sizeof(ListNode));
                strcpy(p->data, ch);
                p->next = NULL; // 这一步真重要,之前一直卡在这里,若没赋空值,赋给p后,进入LocateNode判断会报错,因为q->next->next不是个地址同时也不为空!
                q->next = p;
                q = p;
                // p->next = NULL;
            }
        }
        else 
            break;
    }
    q->next = NULL;
    return head; 
}
结果展示

image-20210916213955278.png

查找

//==========按值查找结点,找到则返回该结点的位置,否则返回NULL==========
ListNode *LocateNode(LinkList head, char *key)
{
    ListNode *p = head->next;
    while (p && strcmp(p->data,key))
    {
        p = p->next;
    }
    return p;
}
结果展示

结合创建、增加、删除操作

image-20210916215137077.png

增加

//==========增加节点=======
ListNode * AddNode(LinkList head)
{
    ListNode *p = head->next;
    printf("Please input Node_data:");
    char ch[10];
    scanf("%s", ch);
    if(LocateNode(head,ch)==NULL) 
    {
        p = (ListNode *)malloc(sizeof(ListNode));
        strcpy(p->data, ch);
        p->next = head->next;
        head->next = p;
    }
    else
        printf("You have already input this Node_data!\n");
    return head;
}
结果展示

image-20210916214753521.png

删除

//==========删除带头结点的单链表中的指定结点=======
void DeleteList(LinkList head, char *key)
{
    ListNode *p = head, *q = NULL;
    while (p && strcmp(p->data,key))
    {
        q = p;
        p = p->next;
    }
    if (p != NULL)
    {
        q->next = p->next;
        free(p);
    }
    else
        printf("结点不存在\n");
}
结果展示

image-20210916214317344.png

打印链表

//===========打印链表=======
void printlist(LinkList head)
{
    ListNode *p=head->next;       //从开始结点打印
    while (p) {
        printf("%s,   ",p->data);
        p=p->next;
    }
    printf("\n");
}

删除所有结点

//==========删除所有结点,释放空间===========
void DeleteAll(LinkList head)
{
    ListNode *p;
    while (head)
    {
        p = head;
        head = head->next;
        free(p);
    }
    printf("All data has been deleted!");
}
结果展示

image-20210916214841505.png

最后修改:2021 年 10 月 25 日
如果觉得我的文章对你有用,请随意赞赏