chapter two 2-5\2-6 链式存储结构的线性表 -- 链表 (插入、查找、初始化、判空等)

2-5 链式存储结构的线性表 – 链表

基本概念:
节点包括数据与和指针域
链表是由n个结点链结成,第一个结点的存储位置叫做头指针,最后一个结点的指针为"空"

typedef struct Monster{
    int id;
    char * name;
    struct Monster * next;      //指向下个节点的指针
}Monster;

void test()
{
    Monster monster1 = {1,"海绵宝宝"};
    Monster monster1 = {2,"xxxx"};
    Monster monster1 = {3,"xx"};
    Monster monster1 = {4,"xx"};
    Monster monster1 = {5,"xxxxxx"};
    
    // monster1 就是头指针
    monster1.next = &monster2;
    monster2.next = &monster3;
    monster3.next = &monster4;
    monster4.next = &monster5;
    monster5.next = NULL;
}

相较于顺序表的优点~:

  1. 不用定义时规定长度
  2. 存储的元素个数不受限制
  3. 插入和删除元素时,不用移动其他元素
链表的头指针和头结点

头指针:链表中第一个阶段的存储位置
头结点:在单链表的第一个结点前附设一个结点

在这里插入图片描述

单链表

基本概念:链表的每一个节点中只包含一个指针域
(单方向的链表)

单链表的读取数据元素
获取第i个结点的数据:
注意:链表的结点编号从1开始有数据 0号索引代表头结点,一般数据域不存放数据

下面上代码:链表初始化 、 插入元素 、 查找、判空、打印等

首先是全局数据结构 DataElement.h
#ifndef DATAELEMENT_H_INCLUDED
#define DATAELEMENT_H_INCLUDED
#define MAX_SIZE 255
/***********************************************************************
 *  Project:数据结构第二章案例
 *  Function:用来定义数据元素
 *  Author:chillinght
 *
 ***********************************************************************
 *  Copyright:2019 by chillinght
 ***********************************************************************
 */

// 1、定义数据元素
//typedef int ElementType;
/*
 *datas = {{1,""},{2,""},{3,""}};
 */
typedef struct{     //这是数据元素中的属性
   int id;
   char *name;
 }ElementType;

 //2、定义顺序表结构
 typedef struct{    //这是顺序表结构的属性
    ElementType datas[MAX_SIZE];//顺序表中的元素集合
    int length;                 //当前顺序表中元素的个数
 }SeqList;


#endif // DATAELEMENT_H_INCLUDED

接下来是单链表头文件(结点&头结点数据结构、函数声明) LinkList.h
#ifndef LINKLIST_H_INCLUDED
#define LINKLIST_H_INCLUDED

/***********************************************************************
 *  Project:数据结构第二章案例
 *  Function:链表抽象数据类型的定义和实现
 *  Description:每个节点都有后继结点,链表的优点是存储空间利用高效
 *  Author:chillinght
 *
 ***********************************************************************
 *  Copyright:2019 by chillinght
 ***********************************************************************
 */

 #include <stdio.h>
 #include <stdlib.h>
 #include "DataElement.h"
 #include <stdbool.h>

 /** 定义链表的结点,包含数据域和指针域  */
 typedef  struct Node{
    ElementType data;           //数据域
    struct Node* next;  //指针域,指向下个结点
 }Node;

 //注意这里定义了链表的结点结构 //但是没有头结点,有时,我们为了更加方便地对链表进行操作,会在单链表的第一个结点前附设一个结点,称为头结点。头结点的数据域可以不存储任何信息,谁叫它是第一个呢,有这个特权。也可以存储如线性表的长度等附加信息,头结点的指针域存储指向第一个结点的指针
/**
 * 下面的结构是用来存储指向第一个非头结点指针和链表长度的
 * 头结点
 * 也叫首元结点,最后一个结点也叫尾元结点,
 * 习惯性的定义头结点,以便统一结点的插入和删除
 */
 typedef struct LinkList{
    Node* next ;                //指针域  也就是头指针(如果有头结点,next指向头结点,没有就指向第一个结点)
    int length;                 //数据域
 }LinkList;

 /** 初始化链表 */
 void InitLinkList(LinkList * linkList,ElementType* dataArray,int length);

  /** 插入方法 */
 void InsertLinkList(LinkList* linklist,ElementType element,int pos);


  /** 打印方法 */
void PrintLinkList(LinkList* linkList);

/** 判断是否为空 */
int IsLinkListEmpty(LinkList* linklist);

/** 查询返回pos位置的循环 */
ElementType GetLinkListElement(LinkList* linklist,int pos);

#endif // LINKLIST_H_INCLUDED


链表操作函数实现文件 LinkList.c
#include "LinkList.h"


 /** 初始化链表 */
void InitLinkList(LinkList * linkList,ElementType* dataArray,int length)
{
    for(int i= 0;i < length;i++){
        InsertLinkList(linkList,dataArray[i],i+1);
    }
    return;
}


/** 插入方法 在pos前面插入*/
/**
 * 向链表插入元素
 * @param linklist      指向头结点的指针-》头指针(头指针指 指向第一个元素的指针,这里第一个元素是头结点)
 * @param element       插入元素  这里的元素是Node结点数据类型中的数据域内容
 * @param pos           插入位置
 */
 void InsertLinkList(LinkList* linklist,ElementType element,int pos)
 {
    //1. 创建空间存储新节点信息
    Node* new_node = (Node*)malloc(sizeof(Node));
    new_node->data = element;
    new_node->next = NULL;
    //2. 找到要插入的位置
    if(pos == 1){                           //如果插入的是第一个元素,由于linklist和node数据结构不一样 需要单独写一下
        new_node->next = linklist->next;
        linklist->next = new_node;
        linklist->length ++;
        //printf("%d\n",linklist->length);
        return;
    }
    // 下面正式开始找位置(pos之前元素的位置)
    Node* p = linklist->next;               //p指向第一个元素
    for(int i = 1;p &&i < pos - 1;i++){
        p = p->next;
    }
    //3.如果能够插入,开始定义结点空间并改变指针域进行连接
    if(!p){//如果pos位置的结点不存在
        printf("该位置不存在\n");
        return;
    }
    else{
        new_node->next = p->next;
        p->next = new_node;
        //现在p已经没用了,已经连上了~ 可以删了p了 别忘了总长度
        p = NULL;
        linklist->length++;
        //printf("%d\n",linklist->length);
        return;
    }

 }
void PrintLinkList(LinkList * linkList)
{
    Node* p = linkList->next;
    if(!p){
        printf("链表为空\n");
        linkList->length = 0;
        return;
    }
    //printf("%d\n",linkList->length);
    for(int i =0;i < linkList->length;i++)
    {
        printf("%d\t%s\n",p->data.id,p->data.name);
        p = p->next;
    }
    p = NULL;
    return;
}

int IsLinkListEmpty(LinkList* linklist)
{
    return linklist->length == 0 ? true : false;
}

ElementType GetLinkListElement(LinkList* linklist,int pos)
{
    Node* p = linklist->next;
    for(int i = 1;p && i < pos;i++){
        p = p->next;
    }
    return p->data;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值