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;
}
相较于顺序表的优点~:
- 不用定义时规定长度
- 存储的元素个数不受限制
- 插入和删除元素时,不用移动其他元素
链表的头指针和头结点
头指针:链表中第一个阶段的存储位置
头结点:在单链表的第一个结点前附设一个结点
单链表
基本概念:链表的每一个节点中只包含一个指针域
(单方向的链表)
单链表的读取数据元素
获取第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;
}