编程语言:c语言
编译环境:Dev-c++
实现功能:实现功能:单链表(带头结点)结点结构体的定义,单链表(带头结点)初始化、求元素个数、插入元素、删除元素、取元素、打印所有元素、就地逆置、撤销的操作。

  • 结构体定义
  • 初始化
  • 求元素个数
  • 插入元素
  • 删除元素
  • 取元素
  • 打印所有元素
  • 就地逆置
  • 撤销
  • 测试及完整代码

结构体定义

定义如下图结点结构体,很显然单链表是链式存储结构,逻辑上相邻的两个元素,物理地址不一定相邻。

typedef struct Node     //定义单链表结点结构体
{DataType data;struct Node *next;
} SLNode;

带头结点单链表结构如下图。

既然涉及到头指针,那当然要区分一下头指针、头结点、首元结点,如下图是带头结点的单链表。

初始化

算法思想:将头·结点的指针域赋为NULL。
为什么使用**head?
首先声明指针就是地址,头指针即我们定义的结构体变量的地址,指针的指针即存放这个地址的内存单元的地址。因为我们要初始化一个头指针,那么我们就要操作它的地址空间,即使用指针的指针。在这个函数中,我们输入头指针的指针,*head即为取这个头指针,(*head) ->next = NULL即为初始化头指针指向结点结构体的指针域值为NULL。对照带头结点单链表结构图,我们可以很清晰的理解。

void ListInitiate(SLNode **head)                       //初始化
{*head = (SLNode*)malloc(sizeof(SLNode));           //申请头节点 (*head) ->next = NULL;                             //置结束标记NULL
} 

求元素个数

算法思想:设置零时指针和计数器,零时指针每移动一位,计数器加一,直到遍历完单链表,返回最终计数值,如下图。

int ListLength(SLNode *head)                         //求当前数据元素个数
{SLNode *p = head;int size = 0;while(p->next != NULL)                             //指针位置移动,size增加 {p = p->next;size++;} return size;} 

插入元素

算法思想:设置零时指针,移动后指向第i-1个元素,再进行连接和断链,如下图。

int ListInsert(SLNode *head,int i,DataType x)        //在第i(0<=i<=size)个位置前插入数据元素值x
{SLNode *p,*q;int j=-1;p=head;while(p->next!=NULL && j<i-1)                   //定位,使p指向第i-1个元素 {p=p->next;j++;}if(j!=i-1)                                        //当i的值不合法时则返回 {printf("插入元素位置参数错!"); return 0; }q = (SLNode *)malloc(sizeof(SLNode));          //申请新结点 q->data = x;                                   //新结点数据域赋值 q->next = p->next;                                //插入步骤① p->next = q;                                    //插入步骤② return 1;}

删除元素

算法思想:设置零时指针,移动后指向第i-1个元素,再进行连接和断链,如下图。

int ListDelete(SLNode *head,int i,DataType *x)       //删除第i(0<=i<=size-1)个位置处的数据元素并保存到x中
{SLNode *p,*s;int j=-1;p=head;while(p->next!=NULL && j<i-1)                   //定位,使p指向第i-1个元素 {p=p->next;j++;}if(j!=i-1)                                        //当i的值不合法时则返回 {printf("插入元素位置参数错!");return 0; }s = p->next;                                    //指针s指向第i个结点 *x=s->data;                                        //把指针s所指结点数据域指赋给x p->next = p->next->next;                        //删除free(s); return 1;  } 

取元素

算法思想:设置零时指针,移动后指向第i-1个元素,再取出下个元素数据域的值。

int ListGet(SLNode *head,int i,DataType *x)          //取第i(0<=i<=size)个位置处的数据元素并保存到x中 ,成功返回1,失败返回0
{SLNode *p;int j=-1;p= head;while(p->next!=NULL && j<i-1)                   //定位,使p指向第i-1个元素 {p=p->next;j++;}if(j!=i-1)                                      //当i的值不合法时则返回 {printf("插入元素位置参数错!");return 0; }    *x = p->next->data;                                  //指针p所指第i个结点数据域的值赋给x return 1; }

打印所有元素

算法思想:设置零时指针遍历单链表,每移动一次打印一个值。

void Print(SLNode *head)                                 //打印单链表
{SLNode *p;p=head;while(p->next!=NULL){printf("%d ",p->next->data);p=p->next;}}

就地逆置

算法思想:设置两个零时指针,首先将头结点断链,然后将剩余的元素逆序插到头结点之后,如下图。

void Reverse(SLNode *head)                           //单链表就地逆置
{SLNode *p,*q;p=head->next;head->next=NULL;                                 //头结点断链 while(p!=NULL)                                     //将元素逆序插到头结点后面 {q=p;p=p->next;q->next=head->next;head->next=q;}} 

撤销

算法思想:释放单链表的结点,需要输入头结点的地址。

void Destory(SLNode **head)                          //撤销单链表
{SLNode *p,*q;p=*head;while(p!=NULL){q=p;p=p->next;free(q);}*head = NULL;
}

测试及完整代码

我们在Dev-c++创建console application的c项目,并添加三个工程文件:test.c,SLNode.c,SLNode.h。步骤如下:

  • 新建项目,选console application(控制台应用程序)、c项目。


  • 给项目添加三个文件,再编译运行。

  
  

运行结果:

完整代码:

test.c:
#include <stdio.h>
#include"SLNode.h"int main()
{int i;int x;SLNode *head;ListInitiate(&head);for(i=0;i<10;i++)                                             //插入10个元素 {ListInsert(head,i,i*i);        }printf("插入10个元素后单链表表中的元素依次为:");Print(head);printf("\n");ListDelete(head,5,&x);                                      //删除第0个位置处元素printf("删除第5个位置处元素后单链表中的元素依次为:");Print(head);printf("\n");printf("删除的元素为:%d",x);printf("\n");ListGet(head,4,&x);                                      printf("取第4个位置处元素元素为:%d",x);printf("\n");Reverse(head);                                               //就地逆置 printf("逆置后单链表中的元素依次为:");Print(head);Destory(&head);return 0;
}
SLNode.h:
#ifndef _SLNODE_H
#define _SLNODE_H
typedef int DataType;typedef struct Node     //定义单链表结点结构体
{DataType data;struct Node *next;
} SLNode;void ListInitiate(SLNode **head);                      //初始化
int ListLength(SLNode *head);                           //求当前数据元素个数
int ListInsert(SLNode *head,int i,DataType x);      //在第i(0<=i<=size)个位置前插入数据元素值x
int ListDelete(SLNode *head,int i,DataType *x);     //删除第i(0<=i<=size)个位置处的数据元素并保存到x中
int ListGet(SLNode *head,int i,DataType *x);            //取第i(0<=i<=size)个位置处的数据元素并保存到x中 ,成功返回1,失败返回0
void Print(SLNode *head);                               //打印单链表
void Reverse(SLNode *head);                             //单链表就地逆置
void Destory(SLNode **head);                             //撤销单链表 #endif
SLNode.c:
#include<stdio.h>
#include<malloc.h>
#include"SLNode.h"void ListInitiate(SLNode **head)                       //初始化
{*head = (SLNode*)malloc(sizeof(SLNode));           //申请头节点 (*head) ->next = NULL;                             //置结束标记NULL
} int ListLength(SLNode *head)                          //求当前数据元素个数
{SLNode *p = head;int size = 0;while(p->next != NULL)                             //指针位置移动,size增加 {p = p->next;size++;} return size;} int ListInsert(SLNode *head,int i,DataType x)      //在第i(0<=i<=size)个位置前插入数据元素值x
{SLNode *p,*q;int j=-1;p=head;while(p->next!=NULL && j<i-1)                   //定位,使p指向第i-1个元素 {p=p->next;j++;}if(j!=i-1)                                        //当i的值不合法时则返回 {printf("插入元素位置参数错!"); return 0; }q = (SLNode *)malloc(sizeof(SLNode));          //申请新结点 q->data = x;                                   //新结点数据域赋值 q->next = p->next;                                //插入步骤① p->next = q;                                    //插入步骤② return 1;} int ListDelete(SLNode *head,int i,DataType *x)       //删除第i(0<=i<=size-1)个位置处的数据元素并保存到x中
{SLNode *p,*s;int j=-1;p=head;while(p->next!=NULL && j<i-1)                   //定位,使p指向第i-1个元素 {p=p->next;j++;}if(j!=i-1)                                        //当i的值不合法时则返回 {printf("插入元素位置参数错!");return 0; }s = p->next;                                    //指针s指向第i个结点 *x=s->data;                                        //把指针s所指结点数据域指赋给x p->next = p->next->next;                        //删除free(s); return 1;  } int ListGet(SLNode *head,int i,DataType *x)           //取第i(0<=i<=size)个位置处的数据元素并保存到x中 ,成功返回1,失败返回0
{SLNode *p;int j=-1;p= head;while(p->next!=NULL && j<i-1)                   //定位,使p指向第i-1个元素 {p=p->next;j++;}if(j!=i-1)                                      //当i的值不合法时则返回 {printf("插入元素位置参数错!");return 0; }    *x = p->next->data;                                  //指针p所指第i个结点数据域的值赋给x return 1; } void Print(SLNode *head)                               //打印单链表
{SLNode *p;p=head;while(p->next!=NULL){printf("%d ",p->next->data);p=p->next;}} void Reverse(SLNode *head)                             //单链表就地逆置
{SLNode *p,*q;p=head->next;head->next=NULL;                                 //头结点断链 while(p!=NULL)                                     //将元素逆序插到头结点后面 {q=p;p=p->next;q->next=head->next;head->next=q;}} void Destory(SLNode **head)                          //撤销单链表
{SLNode *p,*q;p=*head;while(p!=NULL){q=p;p=p->next;free(q);}*head = NULL;
}

  
  


总结一下,单链表中初始化操作的时间复杂度是O(1),其他操作的时间复杂度为O(n),作为链式存储结构的单链表,操作都涉及到指针结构体,所以理解这两个知识点就非常重要了。源代码在我的博客资源区,点击文字链接直达

单链表(带头结点)的存储结构与基本操作(c语言)------亲测可用相关推荐

  1. 链表的特点,单链表的定义、存储结构,单链表的基本操作(判断链表是否为空、销毁链表、清空链表、求链表表长、查找、插入、删除,建立单链表)

    目录 一.链表(链式存储结构)的特点 二.单链表的定义和表示 1.带头结点的单链表 2.单链表的存储结构 三.单链表基本操作的实现 1.单链表的初始化(带头结点的单链表) 2.补充单链表的几个常用简单 ...

  2. 数据结构:单链表——带头结点与不带头结点步骤详解

    单链表:带头结点与不带头结点详解 在本人的另一篇文章中,通过java实现了带头结点和不带头结点的单链表,有兴趣的小伙伴可以去看下数据结构(一):链表(Linked List) 这两天回顾下链表的知识, ...

  3. 单链表———带头结点跟不带头结点的区别

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一.单链表:带头结点跟不带头结点 二.使用步骤 总结 前言 数据结构中单链表的创建 带头结点跟不带头结点的区别 一.单 ...

  4. *循环单链表[带头结点]

    结构(带头结点) 初始化 创建(n个结点) 插入 删除 遍历 销毁 结构: 判空:(head->next==head) 初始化:主要注意链表为空的条件,执行语句:L->next=L; vo ...

  5. 已知一个带有表头的单链表,结点结构为data-link,假设该链表只给出了头指针list。在不改变链表的前提下,请设计一个尽可能高效的算法,查找链表中倒数第k个位置上的结点(k为正整数)。

    今天和大家分享一道2009年代码为408的一道真题: 已知一个带有表头的单链表,结点结构为data-link,假设该链表只给出了头指针list.在不改变链表的前提下,请设计一个尽可能高效的算法,查找链 ...

  6. 写一个函数DeleteRange删除单链表中结点的值在low 和high之间的结点

    /*实验2 1. 写一个函数DeleteRange删除单链表中结点的值在low 和high之间的结点 (low和high的值是多少可自由设计).并且要在程序中验证其功能实现. (可在实验1的第3题的基 ...

  7. 已知线性表最多可能有20个元素,存储每个元素需要8字节,存储每个指针需要4字节。当元素个数为( )时使用单链表比使用数组存储此线性表更加节约空间。

    已知线性表最多可能有20个元素,存储每个元素需要8字节,存储每个指针需要4字节.当元素个数为( 大于等于13 )时使用单链表比使用数组存储此线性表更加节约空间. 使用数组存储线性表需要提前分配好数组空 ...

  8. 狸猫换太子--删除无头单链表中结点

    狸猫换太子–删除无头单链表中结点 @(算法学习) 学习自<编程之美>. 很有意思的一种做法. 给定一个没有头指针的单链表,一个指针指向次单链表中的一个中间结点,删除此结点. 分析:这种根本 ...

  9. 实验一 链式存储结构的基本操作

    广州大学学生实验报告 开课实验室:计算机科学与工程实验(电子楼418A) 2019年4月27日 学院 计算机科学与教育软件学院 年级.专业.班 计算机科学与技术172班 姓名 xxx 学号 17061 ...

最新文章

  1. Java线程池实现原理及其在美团业务中的实践
  2. python根据二叉树的前序遍历和中序遍结果历重建二叉树
  3. CentOS yum 源的配置与使用
  4. Citrix XenDesktop 7.X 视频播放优化
  5. python输入语句-1、python基本的元素及输出语句
  6. 漫画:什么是布隆算法
  7. 重学java基础第六课:markdown语法
  8. atime、ctime 和 mtime区别
  9. 线性代数知识点总结_[Github项目推荐] 机器学习amp; Python 知识点速查表
  10. Jinja2模板引擎语法
  11. CUDA——安装Cython包
  12. mac版Unity Pro游戏开发工具如何创建和使用脚本
  13. VS 和 VAssistX 常用快捷键
  14. Git 操作实战示例
  15. windows利用iis配置反向代理实现ECS内网互通oss
  16. 购买域名不得不注意的事项
  17. MSM7225 600MHZ CPU和高通MSM 7201A 528MHz CPU的比较
  18. CSS技能点--带图标的标题栏
  19. win7怎么用Win10计算机,win7升至win10的电脑,使用半年多后出现各种系统问题,重装还是升级一周年版?...
  20. stm32打怪升级之再见闪烁灯

热门文章

  1. 扭矩大好还是马力大好_马力还是扭矩?老司机:发动机马力大才是硬道理
  2. 推荐一款基于chromium的套壳浏览器——vivaldi
  3. scp命令默认传输速度多大_linux中scp命令使用技巧详解(传输速度)linux操作系统 -电脑资料...
  4. draft-ietf-quic-load-balancers-14
  5. Since your iTunes Connect status is Metadata Rejected, we do NOT require a new binar被拒原因总结
  6. 什么是Hybrid混合器件,如何应用?
  7. java中f是什么意思_1.f是什么意思 - java
  8. 关于华为实名认证的一些常见问题解答
  9. 污水泵站监控管理系统能干什么
  10. 编程英语:常见代码错误 error 语句学习(16)