赞
踩
目录
顺序存储的特点:已物理相邻表示逻辑关系,任一元素均可随机存取。
链式存储的特点:用一组物理位置任意的存储单元来存放线性表的数据元素,这组存储单元可以是连续的也可以是不连续的,甚至可以分布在内存中的任意位置上,链表中元素的逻辑次序和物理次序不一定相同。
两种存储方式可以用下图来辅助理解。
顺序存取:查找第i个位置的数据,需要通过从第一个到第i个,顺序查找,所以存取的时候都是需要按顺序进行,所以叫顺序存取。
随机存取:随便一个i位置的数据,可以通过查找数组第 (i-1)个来查找,存取的时候同样可以存第i个位置或者取第i个位置的元素,所以叫随机存取。
可以用以下图来辅助理解:
单链表,指结点只有一个指针域的链表,也可以称为线性链表。每个单链表都有一个头指针,也就是链表的首地址,其结点分为两个部分,一个是指针域一个是数据域(如下图所示),其中指针域存下一个结点的地址,而数据域为该结点存放的元素。
用单链表的方式来表示线性表,有两种方式,带头结点跟不带头结点。不带头结点,顾名思义就是链表的头指针指向的下一个即为首元素结点;而带头结点的链表则头指针指向头结点,而头结点再指向首元素结点。如下图所示:
带头结点的好处:
便于首元素结点的处理:首元素结点的地址保存在头结点的指针域中,所以在链表中的第一个位置上的操作和其他位置的一致,无需进行特殊处理。
便于空表和非空表的统一处理:无论链表是否为空,头指针都只想头结点的非空指针,因此空表和非空表的处理也就一致了。
单链表定义:用结构体的方式定义,定义一个数据域跟一个指针域。这里实现的是不带头结点的单链表。
这段代码的ElenType为data的类型(相当于结构体的自定义类型);
- typedef int ElemType; //定义数据类型
- typedef struct LNode //声明结点的类型和指向结点的指针类型
- {
- ElemType data; //结点的数据域
- struct LNode* next; //结点的指针域
- }LNode,*LinkList; //LinkList为指向结构体Lnode的指针
注:定义的结构体LNode的类型名称为LNode其指针的为LinkList。即 *LNode = LinkList ,因为后面的函数多数都是对链表的指针域进行操作,所以定义指针类型LinkList方便后面的操作。
定义函数的操作:
-
- #define TRUE 1
- #define FALSE 0
- #define VETERY 1
- #define DEFEAT 0
- #define NOFINE 0
- typedef int Status;
-
- Status InitLinkList(LinkList L); //初始化单链表
- LinkList List_HeadInsert(LinkList L); //头插入法
- LinkList List_TailInsert(LinkList L); //尾插入法
- LNode* GetElem(LinkList L, int i); //按序号查找结点值
- LNode* LocateElem(LinkList L, ElemType e); //按照结点值查找结点
- void Delete_Node(LinkList L, int i); //按序号删除结点
- void Print_Node(LinkList L); //打印单链表
- int Linklength(LinkList L); //计算结点个数
- int ListEmpty(LinkList L); //判断单链表是否为空
- Status ClearList(LinkList L); //清空单链表
- Status DestroyList(LinkList L); //销毁单链表

单链表的基本操作:对单链表进行初始化、建立、判断空值、取值、查找、删除、打印、求表长、清空、销毁十一个操作进行编写代码。
代码块粘贴在最后
初始化,即开辟一个空间,创建单链表的头指针;
- Status InitLinkList(LinkList L) //初始化单链表
- {
- L = (LinkList)malloc(sizeof(LNode)); //开辟一个指针
- L->next = NULL; //单链表没有下一个指针
- return VETERY;
- }
注:(强制转换的类型)malloc(sizeof(类型空间)),malloc是C语言进行开辟空间的函数,如果还不理解的话,可以去看看官方文档的解释。
判断单链表是否为空,只要头指针指向的下一个地址不为空,则还有元素结点在。
- int ListEmpty(LinkList L) //判断单链表是否为空
- {
- if (L->next)
- {
- printf("链表不为空!\n");
- return FALSE;
- }
-
- else
- {
- printf("链表为空!\n");
- return TRUE;
- }
- }
清空单链表
清空单链表采用两个指针进行操作,通过定义p指针为L->next,则为首元素结点,然后用另外一个q指针指向p->next则为第二个元素结点,然后释放p指针free(p),在将q指针赋予给p指针,然后通过不断释放p指针从而实则释放全部的元素结点。下图辅助理解:
- Status ClearList(LinkList L) //清空单链表
- {
- LinkList p, q;
- p = L->next;
- while (p)
- {
- q = p->next;
- free(p);
- p = q;
- }
- L->next = NULL;
- return VETERY;
- }
销毁单链表
销毁单链表将整个单链表的空间都释放掉,因此是从头指针开始往后释放每一个结点。
- Status DestroyList(LinkList L) //销毁单链表
- {
- LinkList p;
- while (L)
- {
- p = L;
- L = L->next;
- free(p);
- }
- return VETERY;
- }
求单链表长度
- int Linklength(LinkList L) //求单链表长度
- {
- int k = 0;
- while (L->next != NULL)
- {
- k++;
- L = L->next;
- }
- return k;
- }
打印单链表
- void Print_Node(LinkList L) //打印单链表
- {
- while (L->next != NULL)
- {
- L = L->next;
- printf("%d ", L->data);
-
- }
- printf("\n");
- }
头插法建立单链表
通过从第一个元素结点进行插入结点,可以由下图辅助理解:
- LinkList List_HeadInsert(LinkList L)//头插入法
- {
- LNode *new;
- int i = 10;
- for (i = 0; i < 10; i++)
- {
- new = (LNode*)malloc(sizeof(LNode)); //开辟一个新指针空间
- new->data = i; //给指针的数据域赋值
- new->next = L->next; //将新结点的下一个指针指向首元素结点,则代替首元素结点
- L->next = new; //头指针指向新结点,即新节点为首元素结点
- }
- return L;
- }
尾插法建立单链表
顾名思义,就是从尾部插入元素,通过下图进行辅助理解:
- LinkList List_TailInsert(LinkList L) //尾插入法
- {
- LNode* new;
- LNode* tail = L;
- for (int i = 0; i < 10; i++)
- {
- new = (LinkList)malloc(sizeof(LNode));
- new->data = i;
- tail->next = new; //将最后一个结点下一个指向new指针
- tail = new; //最后一个指针为new指针
- }
- tail->next = NULL; //最后一个指针指向NULL
- return L;
- }
按序号查找结点值
通过序号 i 来查找相对应的结点值,通过第一个到第 i 个结点,从而返回结点地址,通过结点地址可以获取到对应的结点值。
- LinkList GetElem(LinkList L, int i) //按序号查找结点值
- {
- int j = 1;
- LNode* p = L->next; //定义辅助指针p
- if (i == 0) //如果为0,则返回头指针地址
- return L;
- if (i < 1) //如果小于1则返回NULL空指针
- return NULL;
- while (p && j < i) //在j>=i和p不为NULL之前,循环继续
- {
- p = p->next; //p指下一个指针
- j++; //j+1
- } //查找得到的话为j=i时返回,查找不到,则一直到p为NULL
- return p;
- }
按值查找表结点
通过第一个结点的data开始与目标值e进行对比,直到查找到,则返回结点值。若果没有则返回NULL。
- LinkList LocateElem(LinkList L, ElemType e) //按照结点值查找结点
- {
- LNode* p = L->next;
- while (p->data != e && p != NULL)
- {
- p = p->next;
- }
- return p;
- }
按序号删除结点
通过GetElem函数查找结点的前驱指针,然后将前驱指针 p 指向待删除结点 q 的后继指针,从而释放待删除结点free(q)。通过下图进行辅助理解:
- void Delete_Node(LinkList L, int i) //按序号删除结点
- {
- LinkList p = GetElem(L, i - 1); //查找前驱结点
- LinkList q;
- q = p->next; //令q等于待删除结点
- p->next = q->next; //将p的下一个指向q的下一个
- free(q); //删除q
- }
test.c
- #include "LinkList.h"
-
- int main()
- {
- LNode L; //定义链表L
- InitLinkList(&L); //初始化链表
- //List_HeadInsert(&L); //头插法创建链表
- //Print_Node(&L); //打印链表
- List_TailInsert(&L); //尾插法创建链表
- Print_Node(&L); //打印链表
- LNode* p = GetElem(&L, 3); //查找i = 3 位置的指针
- printf("查找成功3的数据为%d \n", p->data); //打印3位置的元素数据
- LNode* q = LocateElem(&L, 5); //查找值为5的元素的指针
- printf("查找成功5的位置为%p \n", q); //打印查找的指针值
-
- int l = LinkLength(&L); //链表长度
- printf("%d\n", l); //打印链表长度
-
- Delete_Node(&L, 4); //删除i = 4的结点
- printf("删除成功!\n");
- Print_Node(&L); //打印链表
-
- int i = LinkLength(&L);
- printf("%d\n", i); //查看链表长度
-
- ClearList(&L); //清空链表
- if(!ListEmpty(&L)) //判断链表是否为空
- Print_Node(&L); //不为空则打印链表
- return 0;
- }

LinkList.,h
- #pragma once
- #include <stdio.h>
- #include <stdlib.h>
- #define TRUE 1
- #define FALSE 0
- #define VETERY 1
- #define DEFEAT 0
- #define NOFINE 0
-
- typedef int ElemType; //定义数据类型
- typedef int Status;
- typedef struct LNode
- {
- ElemType data; //结点的数据域
- struct LNode* next; //结点的指针域
- }LNode,*LinkList; //LinkList为指向结构体Lnode的指针
-
-
- Status InitLinkList(LinkList L); //初始化单链表
- LinkList List_HeadInsert(LinkList L); //头插入法
- LinkList List_TailInsert(LinkList L); //尾插入法
- LinkList GetElem(LinkList L, int i); //按序号查找结点值
- LinkList LocateElem(LinkList L, ElemType e); //按照结点值查找结点
- void Delete_Node(LinkList L, int i); //按序号删除结点
- void Print_Node(LinkList L); //打印单链表
- int LinkLength(LinkList L); //计算结点个数
- int ListEmpty(LinkList L); //判断单链表是否为空
- Status ClearList(LinkList L); //清空单链表
- Status DestroyList(LinkList L); //销毁单链表

LinkList.c
- #include "LinkList.h"
-
- Status InitLinkList(LinkList L) //初始化单链表
- {
- L = (LinkList)malloc(sizeof(LNode));
- L->next = NULL;
- return VETERY;
- }
- LinkList List_HeadInsert(LinkList L)//头插入法
- {
- LNode *new;
- int i = 10;
- for (i = 0; i < 10; i++)
- {
- new = (LNode*)malloc(sizeof(LNode));
- new->data = i;
- new->next = L->next;
- L->next = new;
- }
- return L;
- }
- LinkList List_TailInsert(LinkList L) //尾插入法
- {
- LNode* new;
- LNode* tail = L;
- for (int i = 0; i < 10; i++)
- {
- new = (LinkList)malloc(sizeof(LNode));
- new->data = i;
- tail->next = new;
- tail = new;
- }
- tail->next = NULL;
- return L;
- }
- LinkList GetElem(LinkList L, int i) //按序号查找结点值
- {
- int j = 1;
- LNode* p = L->next;
- if (i == 0)
- return L;
- if (i < 1)
- return NULL;
- while (p && j < i)
- {
- p = p->next;
- j++;
- }
- return p;
- }
- LinkList LocateElem(LinkList L, ElemType e) //按照结点值查找结点
- {
- LNode* p = L->next;
- while (p->data != e && p != NULL)
- {
- p = p->next;
- }
- return p;
- }
- void Delete_Node(LinkList L, int i) //按序号删除结点
- {
- LNode* p = GetElem(L, i - 1);
- LNode* q;
- q = p->next;
- p->next = q->next;
- free(q);
- }
- void Print_Node(LinkList L) //打印单链表
- {
- while (L->next != NULL)
- {
- L = L->next;
- printf("%d ", L->data);
-
- }
- printf("\n");
- }
- int LinkLength(LinkList L) //求单链表长度
- {
- int k = 0;
- while (L->next != NULL)
- {
- k++;
- L = L->next;
- }
- return k;
- }
- int ListEmpty(LinkList L) //判断单链表是否为空
- {
- if (L->next)
- {
- printf("链表不为空!\n");
- return FALSE;
- }
-
- else
- {
- printf("链表为空!\n");
- return TRUE;
- }
- }
- Status ClearList(LinkList L) //清空单链表
- {
- LinkList p, q;
- p = L->next;
- while (p)
- {
- q = p->next;
- free(p);
- p = q;
- }
- L->next = NULL;
- return VETERY;
- }
- Status DestroyList(LinkList L) //销毁单链表
- {
- LinkList p;
- while (L)
- {
- p = L;
- L = L->next;
- free(p);
- }
- return VETERY;
- }
-

运行截图:
注:当前为单链表的相关操作以及代码展示,链表除了单链表,还有双链表和循环链表,后续学习完再进行学习笔记的编写!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。