C提高7—链表与指针

本文探讨了链表与指针的关系,强调了链表在内存管理上的优势,如无需连续存储区域和高效的插入删除操作。文章介绍了链表的data域和指针域,包括动态链表和静态链表的不同,以及带头链表和不带头链表的实现。此外,还详细讲解了如何创建头节点、遍历链表以及进行链表的基本操作,如插入和删除结点的函数实现。
摘要由CSDN通过智能技术生成

链表与指针

  • 为什么要学习链表
    数组:一次性分配一块连续的存储区域
    数组的优点:
    随机访问元素效率高
    数组的缺点:
    需要分配一块连续的存储区域(很大区域,有可能分配失败)
    删除和插入某个元素效率低

链表:现实生活中的灯笼
链表优点:
不需要一块连续的存储区域
删除和插入某个元素效率高
链表缺点:
随机访问元素效率低

链表的data域和指针域

动态链表和静态链表
带头链表和不带头链表
单向链表、双向链表
## 结构体套结构体

 typedef struct A 
 {
     int a;
     int b;
     char *p;
 }A;
/*1、结构体可以嵌套另一个结构体的任何类型变量
2、结构体嵌套本结构体普通变量(不可以),因为结构体的本质是固定大小的内存块别名,如果结构体嵌套本结构体,那么本结构体的类型大小无法确定。
3、结构体嵌套本结构体指针变量(可以,因为指针变量的类型能确定)
*/
 typedef struct B 
 {
     int a;
     int b;
     char *p;
     A temp1;  //ok
     A *p1;   //ok
     B temp2;  //err
     B *next;  //ok  32位,4字节,64位,8字节
 }B;

静态链表的用法

#define _CRT_SECURE_NO_WARNINGS
#include "stdafx.h"


typedef struct Stu
{
    int id;//数据域
    char name[100];
     Stu *next;  //指针域
}Stu;



int main()
{
    //初始化三个结构体变量
    Stu s1 = { 1,"mike",NULL };
    Stu s2 = { 2,"Lily",NULL };
    Stu s3 = { 3,"lilei",NULL };

    s1.next = &s2;
    s2.next = &s3;
    s3.next = NULL;

    Stu *p = &s1;
    while (p != NULL)
    {
        printf("id = %d,name = %s\n", p->id, p->name);
        p = p->next;  //结点往后移一位
      }


    printf("\n");
    system("pause");
    return 0;
}

这里写图片描述

头节点的创建和链表的遍历

基本操作

  • 建立带有头结点的单向链表
    编写函数SList_Creat,建立带有头节点的单向链表。循环创建结点,结点数据域中的数值从键盘输入,以-1作为输入结束标志。链表的头结点地址由函数返回值返回。
  • 顺序访问链表中各结点的数据域
    编写函数SList_Print,顺序输出单向链表各项结点数据域中的内容。
#define _CRT_SECURE_NO_WARINGS
#include "stdafx.h"

typedef struct Node
{
    int id;
    struct Node *next; //指针域
}Node;

 //下面通过函数*SListCreat()创建头结点
Node *SListCreat()
{
    Node *head = NULL;
    //头结点作为标志,不存储有效数据
    head = (Node *)malloc(sizeof(Node));
    if (head == NULL)
    {
        return NULL;
    }
    //给head的成员变量赋值
    head->id = -1;
    head->next = NULL;

    //下面定义两个辅助变量  
    Node *pCur = head;
    Node *pNew = NULL;

    int data;
    while (1)
    {
        printf("请输入数据:");
        scanf_s("%d", &data);
        if (data == -1)
        {
            break;
        }
        pNew = (Node *)malloc(sizeof(Node)); //新结点动态分配空间
        if (pNew == NULL)
        {
            continue;
        }

        //给pNew成员变量赋值
        pNew->id = data;
        pNew->next = NULL;

        //下面3条语句是重点,链表建立关系
        pCur->next = pNew;//当前结点的next指向pNew
        pNew->next = NULL;//pNew的下一个结点指向NULL
        pCur = pNew;   //把pCur移动到pNew,pCur指向pNew

    }


    return head;   //链表的头结点地址由函数返回值返回
}

//链表的遍历
int SListPrint(Node *head)
{
    if (head == NULL)
    {
        return -1;
    }
    //取出第一个有效结点(头结点的next)
    Node *pCur = head->next;
    printf("head->");
    while (pCur != NULL)
    {
        printf("%d->", pCur->id);
        //当前结点往后移动一位,pCur指向下一个结点
        pCur = pCur->next;
    }
    printf("NULL\n");
    return 0;
}




int main()
{

    Node *head = NULL;
    head = SListCreat();
    SListPrint(head);

    printf("\n");
    system("pause");
    return 0;
}

结果如下:
这里写图片描述

  • 在单向链表中插入结点
    编写函数SList_NodeInsert,功能:在值为x的结点前,插入值为y的结点;若值为x的结点不存在,则插在表层。
    这里写图片描述
int SListNodeInsert(Node *head, int x, int y)
{
    if (head == NULL)
    {
        return -1;
    }
    Node *pPre = head;
    Node *pCur = head->next;

    while (pCur != NULL)
    {
        if (pCur->id == x)  //找到了匹配结点
        {
            break;
        }
        //如果还没找到匹配结点,则往下执行
        pPre = pCur;//pPre指向pCur的位置
        pCur = pCur->next; //pCur指向下一个结点

    }  //结果有2种情况 
       //1.找到匹配的结点,pCur为匹配结点,pPre为pCur上一个结点
       //2.没有找到匹配结点,pCur为空结点,pPre为最后一个结点

    //给新结点动态分配空间
    Node *pNew = (Node *)malloc(sizeof(Node));
    if (pNew == NULL)
    {
        return -2;
    }

    //给pNew的成员变量赋值
    pNew->id = y;
    pNew->next = NULL;

    //插入到指定位置      关键语句
    pPre->next = pNew;  //pPre下一个指向pNew
    pNew->next = pCur;  //pNew下一个指向pCur

    return 0;
}

将上面这段程序加入到“建立带有头结点的单向链表和顺序访问链表中各结点的数据域”的程序中,并在main函数中加入以下两条语句:

SListNodeInsert(head, 5, 4);
    printf("在5的前面插入4后\n");
    SListPrint(head);

就可以实现在链表中插入结点的功能啦~
实现结果如下:
这里写图片描述

  • 删除单向链表中的结点
    编写函数SList_NodeDel,删除值为x的结点。
    这里写图片描述
//删除第一个值为x的结点
int SList_NodeDel(SLIST *pHead, int y)
{
    SLIST  *pCur, *pPre;

    //初始化状态

    pPre = pHead;
    pCur = pHead->next;

    while(pCur != NULL)
    {
        if (pCur->data == y)
        {
            break;
        }
        pPre = pCur;
        pCur = pCur->next;
    }

    //删除操作
    if (pCur == NULL)
    {
        printf("没有找到结点值为:%d 的结点\n", y);
        return -1;
    }
    pPre->next = pCur->next;
    if (pCur != NULL)
    {
        free(pCur);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值