无头结点的单链表(C语言)
1.单链表:
在顺序表中,用一组地址连续的存储单元来一次存放线性表的结点,因此结点的逻辑顺序与物理顺序是一致的。但链表却不同,链表是用一组任意的存储单元来存放 线性表的结点,这组存储单元可以是连续的,也可以是非连续的,甚至是零散分布在内存的任何位置上。因此,链表中结点的逻辑顺序与物理顺序不一定相同。为了正确表示节点间的逻辑关系,必须在存储线性表的每个数据元素的同时,存储指示其后继结点的地址信息,这两部分信息共同构成了单链表结点的结构,如下图:

结点包括两个域,数据域用来存放结点的值,指针域用来存储数据元素的直接后继的地址(或位置)。线性表正是通过每个结点的指针域将线性表的n个结点按其逻辑顺序连接在一起的。由于此线性表的每个节点只有一个next指针域,故将这种链表叫做单链表。
由于单链表中的每一个结点除了第一个节点外,它们的存储地址存放在其前驱结点的指针域中,由于第一个节点无前驱,所以应该设一个头指针指向第一个节点,本文中设置了first指针指向第一个结点。单链表中的最后一个节点无直接后继,所以指定单链表的最后一个结点的指针域为"空"(NULL)。
一般情况下,使用链表,只关心链表中结点的逻辑顺序,并不关心每个结点的实际存储位置,因此通常用箭头来表示链域中的指针,于是链表就可以更直观地画成用箭头链接起来的结点序列,如图:
有时候,为了操作的统一方便,可以在单链表的第一个结点前附设一个头结点,头结点的数据域可以存储一些关于线性表的长度等附加信息,也可以不存储任何信息,对头结点的数据域无特别规定,而头结点的指针域用来存储指向第一个结点的指针(即第一个结点的存储位置)。如果线性表为空,则头结点的指针域为"空"。如图所示:

2.单链表操作:
头插过程:

头插的方式如上图所示。采用头插法得到的单链表的逻辑顺序与输入元素顺序相反,亦称头插法为逆序建表法。在这只介绍头插法的示意图,对于尾插、头删、尾删、可以参考《数据结构----用C语言描述》(耿国华主编)这本书。下面的代码中,实现了头插、尾插、头删、尾删,读者可以仔细研究研究。(本文所编写的代码是在VS2013编译环境下运行的)
3.运行代码:
Linklist.h文件包括各个操作函数的声明以及包含的头文件,test.c包含了测试代码,Linklist.c文件里主要是各个操作函数的具体实现。
//Linklist.h
#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h> typedef int LDataType;
typedef struct Linklist
{
LDataType data;
struct Linklist *next;
}Linklist, *pLinklist; //接口函数
pLinklist BuyNewNode(LDataType data);//动态生成新节点
void InitLinklist(pLinklist *pL);//初始化单链表
void PushBackLinklist(pLinklist *pL, LDataType data);//尾插
void PushFrontLinklist(pLinklist *pL, LDataType data);//头插
void PopBackLinklist(pLinklist *pL);//尾删
void PopFrontLinklist(pLinklist *pL);//头删
void PrintLinklist(Linklist *pL);//打印单链表
pLinklist FindLinklist(pLinklist *pL, LDataType data);//查找指定元素,返回指定元素的位置
void InsertLinklist(pLinklist *pL, pLinklist p, LDataType data);//指定位置插入
void RemoveLinklist(pLinklist *pL, LDataType data);//删除第一个指定元素
void RemoveAllLinklist(pLinklist *pL, LDataType data);//删除所有的指定元素
int IsEmptyLinklist(pLinklist pL);//判断链表是否为空,为空返回1;不为空返回0;
void DestoryLinklist(pLinklist *pL);//销毁单链表
//Linklist.c
#include"Linklist.h"
pLinklist BuyNewNode(LDataType data)//生成新节点
{
pLinklist NewNode = (pLinklist)malloc(sizeof(Linklist));
if (NewNode == NULL)
{
printf("动态开辟内存空间失败\n");
return;
}
NewNode->data = data;
NewNode->next = NULL;
return NewNode;
}
void InitLinklist(pLinklist *pL)//初始化
{
assert(pL != NULL);
(*pL) = NULL;
}
void PushBackLinklist(pLinklist *pL, LDataType data)//尾插
{
assert(pL != NULL);
pLinklist NewNode = BuyNewNode(data);
if (*pL == NULL)
{
*pL = NewNode;
return;
}
pLinklist cur = *pL;
while (cur->next)
{
cur = cur->next;
}
cur->next = NewNode;
}
void PushFrontLinklist(pLinklist *pL, LDataType data)//头插
{
assert(pL != NULL);
pLinklist NewNode = BuyNewNode(data);
if (*pL == NULL)
{
*pL = NewNode;
return;
}
NewNode->next = *pL;
*pL = NewNode;
}
int IsEmptyLinklist(pLinklist pL)//判断是否为空链表
{
if (pL == NULL)
return ;
return ;
}
void PopBackLinklist(pLinklist *pL)//尾删
{
assert(pL != NULL);
if (IsEmptyLinklist(*pL))//链表为空,没有节点
{
printf("链表为空,删除操作失败\n");
return;
}
pLinklist cur = *pL;
pLinklist pre = NULL;//保存cur的前一个节点
if (cur->next == NULL)//有一个节点
{
*pL = NULL;
free(cur);
cur = NULL;
return;
}
while (cur->next)
{
pre = cur;
cur = cur->next;
}
pre->next = NULL;
free(cur);
cur = NULL;
}
void PopFrontLinklist(pLinklist *pL)//头删
{
assert(pL != NULL);
if (*pL == NULL)
{
printf("链表为空,删除操作失败\n");
return;
}
pLinklist cur = *pL;
*pL = cur->next;
free(cur);
cur = NULL;
}
pLinklist FindLinklist(pLinklist *pL, LDataType data)//查找指定元素,返回指定元素的位置
{
assert(pL != NULL);
pLinklist cur = *pL;
while (cur)
{
if (cur->data == data)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
void InsertLinklist(pLinklist *pL, pLinklist p, LDataType data)//指定位置前面插入
{
assert(pL != NULL);
pLinklist NewNode = BuyNewNode(data);
pLinklist cur = *pL;
while (cur->next != p)
{
cur = cur->next;
}
NewNode->next = p;
cur->next = NewNode;
}
void RemoveLinklist(pLinklist *pL, LDataType data)//删除第一个指定元素
{
assert(pL != NULL);
pLinklist cur = NULL;
pLinklist p = *pL;
pLinklist pre = NULL;
cur = FindLinklist(pL, data);//找到要删除的指定元素
if (cur == NULL)
{
printf("没找到要删除的指定元素,删除失败\n");
return;
}
if (*pL == cur)//位于第一个节点
{
*pL= cur->next;
free(cur);
cur = NULL;
return;
}
while (p!= cur)
{
pre = p;
p = p->next;
}
pre->next = cur->next;
free(cur);
cur = NULL;
}
void RemoveAllLinklist(pLinklist *pL, LDataType data)//删除所有的指定元素
{
assert(pL != NULL);
pLinklist cur = NULL;
pLinklist p = *pL;
pLinklist pre = *pL;
while (p)
{ if (p->data == data && (*pL) == p)
{
pre = p;
p = p->next;
*pL = p;
free(pre);
pre = NULL;
}
else if (p->data == data)
{
cur = p;
p = p->next;
pre->next = p;
free(cur);
cur = NULL;
}
else
{
pre = p;
p = p->next;
}
} }
void PrintLinklist(Linklist *pL)//打印单链表
{
pLinklist cur = pL;
while (cur)
{
printf("%d-->", cur->data);
cur = cur->next;
}
printf("NULL\n");
}
void DestoryLinklist(pLinklist *pL)//销毁单链表,放置内存溢出
{
assert(pL != NULL);
pLinklist cur = *pL;
pLinklist pre = NULL;//保存cur的前一个节点
if (*pL == NULL)
{
printf("链表为空\n");
return;
}
if (cur->next == NULL)//只有一个节点
{
*pL = NULL;
free(cur);
cur = NULL;
return;
}
while (cur)
{
pre = cur;
cur = cur->next;
free(pre);
pre = NULL;
}
}
//test.c测试函数
#include"Linklist.h" void test()
{
pLinklist cur = NULL;//用来接收FindLinklist的返回值
Linklist *first = NULL;
InitLinklist(&first);//初始化
//PushBackLinklist(&first, 1);//尾插元素
//PushBackLinklist(&first, 2);
//PushBackLinklist(&first, 3);
//PushBackLinklist(&first, 4);
//PushBackLinklist(&first, 5);
//PrintLinklist(first);//打印单链表
PushFrontLinklist(&first, );//头插元素
PushFrontLinklist(&first, );
PushFrontLinklist(&first, );
PushFrontLinklist(&first, );
PushFrontLinklist(&first, );
//PopBackLinklist(&first);//尾删一个节点
//PopFrontLinklist(&first);//头删一个节点
//PrintLinklist(first);//打印单链表
//DestoryLinklist(&first);
//cur = FindLinklist(&first, 8);
//InsertLinklist(&first, cur, 11);
//printf("在8前面插入11得:");
//PrintLinklist(first);//打印单链表
//printf("删除11得:");
//RemoveLinklist(&first, 11);
//PrintLinklist(first);
PushFrontLinklist(&first, );
PushFrontLinklist(&first, );
//RemoveLinklist(&first, 7);
RemoveAllLinklist(&first, );
PrintLinklist(first); //RemoveAllLinklist(&first, 7);//删除所有的7
}
int main()
{
test();
system("pause");
return ;
}
4.尾插法建立单链表如下图:
测试图: 运行图:

5.头插法建立单链表如下图:
测试图: 运行图:

6.头删和尾删一个结点:
测试图: 运行图:

7.在指定位置插入元素:
测试图: 运行图:

除这几个操作外,还有删除指定元素RemoveLinklist(删除第一个找到的指定元素),删除所有的指定元素RemoveAllLinklist。因为本文中单链表的结点是动态开辟的,因此还要实现销毁函数DestoryLinklist,防止内存泄漏。
无头结点的单链表(C语言)的更多相关文章
- 不带头结点的单链表------C语言实现
File name:no_head_link.c Author:SimonKly Version:0.1 Date: 2017.5.20 Description:不带头节点的单链表 Funcion L ...
- 不带头结点的单链表(基于c语言)
本篇文章的代码大多使用无头结点的单链表: 相关定义: #include <stdio.h> #include <stdlib.h> #include <assert.h& ...
- c语言实现--不带头结点的单链表操作
1,不带头结点的单链表操作中,除了InitList(),GetElem(),ListInsert(),ListDelete()操作与带头结点的单链表有差别外,其它的操作基本上一样. 2,不带头结点单链 ...
- java编写带头结点的单链表
最近在牛客网上练习在线编程,希望自己坚持下去,每天都坚持下去练习,给自己一个沉淀,不多说了 我遇到了一个用java实现单链表的题目,就自己在做题中将单链表完善了一下,希望大家作为参考也熟悉一下,自己 ...
- 单链表 C语言 学习记录
概念 链接方式存储 链接方式存储的线性表简称为链表(Linked List). 链表的具体存储表示为: 用一组任意的存储单元来存放线性表的结点(这组存储单元既可以是连续的,也可以是不连续的). 链表中 ...
- C/C++中创建(带头结点、不带头结点的)单链表
1.带头结点的单链表(推荐使用带头结点的单链表)(采用尾插法) 了解单链表中节点的构成 从上图可知,节点包含数据域和指针域,因此,在对节点进行定义时,我们可以如下简单形式地定义: /* 定义链表 */ ...
- 链表习题(2)-一个集合用带头结点的单链表L表示,编写算法删除其值最大的结点。
/*一个集合用带头结点的单链表L表示,编写算法删除其值最大的结点.*/ /* 算法思想:使用pre,p,premax,max四个指针,pre和p进行比较,premax和max进行最后的删除操作 通过遍 ...
- 链表习题(1)-设计一个递归算法,删除不带头结点的单链表L中所有值为x的结点
/*设计一个递归算法,删除不带头结点的单链表L中所有值为x的结点*/ /* 算法思想:设f(L,x)的功能是删除以L为首结点指针的单链表中所有值等于x的结点, 则显然有f(L->next,x)的 ...
- 有一个线性表,采用带头结点的单链表L来存储,设计一个算法将其逆置,且不能建立新节点,只能通过表中已有的节点的重新组合来完成。
有一个线性表,采用带头结点的单链表L来存储,设计一个算法将其逆置,且不能建立新节点,只能通过表中已有的节点的重新组合来完成. 分析:线性表中关于逆序的问题,就是用建立链表的头插法.而本题要求不能建立新 ...
随机推荐
- struts2用到的jar有那些
struts2.0 lib/antlr-2.7.6.jarlib/struts2-core-2.0.14.jarlib/struts2-spring-plugin-2.0.14.jarlib/free ...
- 关于IBatisNet的配置文件中数据库连接字符串加密处理
我们通常在IBatisNet配置文件 properties.config 加入数据库连接字符串.数据库连接字符串直接放在里面,没有被加密,很不安全.如果我们把 properties.config 文件 ...
- jQuery nyroModal 插件遇到问题
nyroModal ver 1.6.2 弹出层插件 浏览更多 初始化大小问题 //页面加载完成后初始化 设置大小 $(function() { $.nyroModalSettings({ widt ...
- [转载红鱼儿]delphi 实现微信开发(2)接入微信公众号平台
先要学习一下接入的资料,在这里,因为原理都在,所以一定要认真阅读,然后,利用Delphi实现一个对应函数,然后申请微信公众平台接口测试帐号. function CheckSignature(const ...
- EF生成的SQL语句执行顺序问题。
//实体被更改后,再做删除,EF只生成删除语句 //实体删除后再更改,EF报错 //添加语句会再,更改,删除后执行,更AddObject位置无关 //一个实体多个字段被改,只会生成一句update / ...
- sql join用法(转)
left join(左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录 right join(右联接) 返回包括右表中的所有记录和左表中联结字段相等的记录inner join(等值连接) 只 ...
- 进度条ProgressBar
在本节中,作者只写出了进度条的各种样式,包括圆形.条形,还有自定义的条形,我想如果能让条形进度条走满后再继续从零开始,于是我加入了一个条件语句.作者的代码中需要学习的是handler在主线程和子线程中 ...
- HDU 4355 Party All the Time (三分求极值)
题意:给定x轴上有n个点,每一个点都有一个权值,让在x轴上选一个点,求出各点到这个点的距离的三次方乘以权值最小. 析:首先一开始我根本不会三分,也并没有看出来这是一个三分的题目的,学长说这是一个三分的 ...
- python读取文件另存为
fr = open(filename_r,encoding='cp852') w2 = open(filename_w,'a')#a代表追加 w代表重写 for line in fr: w2.writ ...
- Codeforces801A Vicious Keyboard 2017-04-19 00:16 241人阅读 评论(0) 收藏
A. Vicious Keyboard time limit per test 2 seconds memory limit per test 256 megabytes input standard ...