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语言)的更多相关文章

  1. 不带头结点的单链表------C语言实现

    File name:no_head_link.c Author:SimonKly Version:0.1 Date: 2017.5.20 Description:不带头节点的单链表 Funcion L ...

  2. 不带头结点的单链表(基于c语言)

    本篇文章的代码大多使用无头结点的单链表: 相关定义: #include <stdio.h> #include <stdlib.h> #include <assert.h& ...

  3. c语言实现--不带头结点的单链表操作

    1,不带头结点的单链表操作中,除了InitList(),GetElem(),ListInsert(),ListDelete()操作与带头结点的单链表有差别外,其它的操作基本上一样. 2,不带头结点单链 ...

  4. java编写带头结点的单链表

    最近在牛客网上练习在线编程,希望自己坚持下去,每天都坚持下去练习,给自己一个沉淀,不多说了 我遇到了一个用java实现单链表的题目,就自己在做题中将单链表完善了一下,希望大家作为参考也熟悉一下,自己 ...

  5. 单链表 C语言 学习记录

    概念 链接方式存储 链接方式存储的线性表简称为链表(Linked List). 链表的具体存储表示为: 用一组任意的存储单元来存放线性表的结点(这组存储单元既可以是连续的,也可以是不连续的). 链表中 ...

  6. C/C++中创建(带头结点、不带头结点的)单链表

    1.带头结点的单链表(推荐使用带头结点的单链表)(采用尾插法) 了解单链表中节点的构成 从上图可知,节点包含数据域和指针域,因此,在对节点进行定义时,我们可以如下简单形式地定义: /* 定义链表 */ ...

  7. 链表习题(2)-一个集合用带头结点的单链表L表示,编写算法删除其值最大的结点。

    /*一个集合用带头结点的单链表L表示,编写算法删除其值最大的结点.*/ /* 算法思想:使用pre,p,premax,max四个指针,pre和p进行比较,premax和max进行最后的删除操作 通过遍 ...

  8. 链表习题(1)-设计一个递归算法,删除不带头结点的单链表L中所有值为x的结点

    /*设计一个递归算法,删除不带头结点的单链表L中所有值为x的结点*/ /* 算法思想:设f(L,x)的功能是删除以L为首结点指针的单链表中所有值等于x的结点, 则显然有f(L->next,x)的 ...

  9. 有一个线性表,采用带头结点的单链表L来存储,设计一个算法将其逆置,且不能建立新节点,只能通过表中已有的节点的重新组合来完成。

    有一个线性表,采用带头结点的单链表L来存储,设计一个算法将其逆置,且不能建立新节点,只能通过表中已有的节点的重新组合来完成. 分析:线性表中关于逆序的问题,就是用建立链表的头插法.而本题要求不能建立新 ...

随机推荐

  1. Devexpress VCL Build v2014 vol 14.2.6 发布

    终于支持XE8 了.需要这么长时间吗? New Major Features in 14.2 What's New in VCL Products 14.2 Feature Highlights To ...

  2. 482. License Key Formatting

    static int wing=[]() { std::ios::sync_with_stdio(false); cin.tie(NULL); ; }(); class Solution { publ ...

  3. 2018.09.30 bzoj2741: 【FOTILE模拟赛】L(分块+可持久化01trie)

    传送门 数据结构经典题. 首先考虑另外一种询问方式. 已知权值val,在区间[1,n][1,n][1,n]中找一个数使得valvalval^a[i]a[i]a[i]最大. 这个可以直接01trie. ...

  4. 2018.09.09 UVa10529 - Dumb Bones(期望dp)

    传送门 期望dp好题. f[i]表示摆放i个的最小花费,于是f[i]可以从f[j]与f[i-j+1]转移过来了. 代码: #include<bits/stdc++.h> #define N ...

  5. 着重基础之—构建工具—Maven的依赖管理

    着重基础之—构建工具—Maven的依赖管理 项目构建利器Maven给我们开发人员带来了极大的便利,从繁琐的jar包管理中脱身的程序员终于可以有时间再进入另一个坑了. 我今天要给大家分享的内容是我在实际 ...

  6. ImageResizer 3.4.3配置

    <?xml version="1.0" encoding="utf-8"?> <!-- For more information on how ...

  7. 文件读取ndarry 等价于DataFrame的操作

    LD=loadDatas() userMat=LD.makeRatingMatWithoutUserID() print(type(userMat)) userRatingMat=pd.DataFra ...

  8. SPSS-比较均值-独立样本T检验 案例解析

    在使用SPSS进行单样本T检验时,很多人都会问,如果数据不符合正太分布,那还能够进行T检验吗?而大样本,我们一般会认为它是符合正太分布的,在鈡型图看来,正太分布,基本左右是对称的,一般具备两个参数,数 ...

  9. Python安装setuptools遇到的MARKER_EXPR错误

    # python setup.py install Traceback (most recent call last):   File "setup.py", line 11, i ...

  10. faceswap安装说明

    Installing Faceswap Installing Faceswap Prerequisites Hardware Requirements Supported operating syst ...