基础链表实现

news/2024/7/4 13:05:09
  • 前言

最近在复习数据结构的相关知识,感觉在初学的时候还是有很多东西没有掌握,不过现在终于算是搞得比较有头绪了,所以就在写出来和大家一起分享!

  • 什么是链表

简单的说,链表就是由多个结点离散分配,彼此通过指针相连,每个结点只有一个前驱结点和后继结点。首节点无前驱结点,为结点无后继结点的一种存储结构。

  • 链表的结构

数据结构之链表(C实现)

头结点:链表的第一个有效结点前面的结点,头结点并不存放有效数据,也就是数据域为空,加头结点的主要目的是为了方便链表的操作。

首节点:链表的第一个有效结点,结点包含数据域和指针域。

尾结点:尾结点的指针域为空。

头指针:指向头结点的指针变量,它存放了头结点的地址(在这里注意一下,指针变量存放的是地址,也就是说头指针存放的是头结点的地址,一般通过头指针对链表进行操作)。

  • 具体实现

#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
//定义链表节点
typedef struct Node
{
 int data;    //数据域
 struct Node * pNext; //指针域
}NODE, * PNODE;    //NODE等价于struct Node, PNODE等价于struct Node *

//函数声明
PNODE createLinkList(void);        //创建链表的函数
void traverseLinkList(PNODE pHead);      //遍历链表的函数
bool isEmpty(PNODE pHead);        //判断链表是否为空的函数
int getLength(PNODE pHead);        //获取链表长度的函数
bool insertElement(PNODE pHead, int pos, int val);  //向链表中插入元素的函数,三个参数依次为链表头结点、要插入元素的位置和要插入元素的值
bool deleteElement(PNODE pHead, int pos, int * pVal); //从链表中删除元素的函数,三个参数依次为链表头结点、要删除的元素的位置和删除的元素的值
void sort(PNODE pHead);         //对链表中的元素进行排序的函数(基于冒泡排序)
int main(void)
{
 int val;     //用于保存删除的元素
 PNODE pHead = NULL;   //PNODE等价于struct Node *
 pHead = createLinkList(); //创建一个非循环单链表,并将该链表的头结点地址赋给pHead
 traverseLinkList(pHead); //调用遍历链表的函数
 if(isEmpty(pHead))
  printf("链表为空!\n");
 else
  printf("链表不为空!\n");
 printf("链表的长度为:%d\n", getLength(pHead));
 //调用冒泡排序函数
 sort(pHead);
 //重新遍历
 traverseLinkList(pHead);
 //向链表中指定位置处插入一个元素
 if(insertElement(pHead, 4, 30))
  printf("插入成功!插入的元素为:%d\n", 30);
 else
  printf("插入失败!\n");
 //重新遍历链表
 traverseLinkList(pHead);
 //删除元素测试
 if(deleteElement(pHead, 3, &val))
  printf("元素删除成功!删除的元素是:%d\n", val);
 else
  printf("元素删除失败!\n");

 traverseLinkList(pHead);
 system("pause");
 return 0;
}

PNODE createLinkList(void)
{
 int length;  //有效结点的长度
 int i;
 int value;  //用来存放用户输入的结点的值
 //创建了一个不存放有效数据的头结点
 PNODE pHead = (PNODE)malloc(sizeof(NODE));//分配内存
 if(NULL == pHead)
 {
  printf("内存分配失败,程序退出!\n");
  exit(-1);
 }
 PNODE pTail = pHead; //pTail始终指向尾结点   开始都指向新分配的内存,插入节点后头节点指针指向内存不变但是尾节点指向新分配的内存
 pTail->pNext = NULL; //清空指针域
 printf("请输入您想要创建链表结点的个数:len = ");
 scanf("%d", &length);
 for(i=0;i<length;i++)
 {
  printf("请输入第%d个结点的值:", i+1);
  scanf("%d", &value);
  PNODE pNew = (PNODE)malloc(sizeof(NODE));
  if(NULL == pHead)
  {
   printf("内存分配失败,程序退出!\n");
   exit(-1);
  }
  pNew->data = value;  //向新结点中放入值
  pTail->pNext = pNew; //将尾结点指向新结点
  pNew->pNext = NULL;  //将新结点的指针域清空
  pTail = pNew;   //将新结点赋给pTail,使pTail始终指向为尾结点
 }
 return pHead;
}

void traverseLinkList(PNODE pHead)
{
 PNODE p = pHead->pNext;
 while(NULL != p)
 {
  printf("%d  ", p->data);
  p = p->pNext;
 }
 printf("\n");
 return;
}

bool isEmpty(PNODE pHead)
{
 if(NULL == pHead->pNext)
  return true;
 else
  return false;
}

int getLength(PNODE pHead)
{
 PNODE p = pHead->pNext;   //指向首节点
 int len = 0;     //记录链表长度的变量
 while(NULL != p)
 {
  len++;
  p = p->pNext;    //p指向下一结点
 }
 return len;
}

void sort(PNODE pHead)
{
 int len = getLength(pHead);  //获取链表长度   
 int i, j, t;     //用于交换元素值的中间变量
 PNODE p, q;      //用于比较的两个中间指针变量
 for(i=0,p=pHead->pNext ; i<len-1 ; i++,p=p->pNext)
 {
  for(j=i+1,q=p->pNext;j<len;j++,q=q->pNext)
  {
   if(p->data > q->data)
   {
    t = p->data;
    p->data = q->data;
    q->data = t;
   }
  }
 }
 return;
}

bool insertElement(PNODE pHead, int pos, int val)
{
 int i = 0;
 PNODE p = pHead;
 //判断p是否为空并且使p最终指向pos位置的结点
 while(NULL!=p && i<pos-1)
 {
  p = p->pNext;
  i++;
 }
 if(NULL==p || i>pos-1)
  return false;
 //创建一个新结点
 PNODE pNew = (PNODE)malloc(sizeof(NODE));
 if(NULL == pNew)
 {
  printf("内存分配失败,程序退出!\n");
  exit(-1);
 }
 pNew->data = val;
 //定义一个临时结点,指向当前p的下一结点
 PNODE q = p->pNext;
 //将p指向新结点
 p->pNext = pNew;
 //将q指向之前p指向的结点
 pNew->pNext = q;
 return true;
}

bool deleteElement(PNODE pHead, int pos, int * pVal)
{
 int i = 0;
 PNODE p = pHead;
 //判断p是否为空并且使p最终指向pos结点
 while(NULL!=p->pNext && i<pos-1)
 {
  p = p->pNext;
  i++;
 }
 if(NULL==p->pNext || i>pos-1)
  return false;
 //保存要删除的结点
 * pVal = p->pNext->data;
 //删除p后面的结点
 PNODE q = p->pNext;
 p->pNext = p->pNext->pNext;
 free(q);
 q = NULL;
  return true;
}

  • 结尾语

上面实现的主要是单链表,另外还有双链表、循环链表、非循环链表等其他几种常见链表。双链表的特殊性表现在每个基本结点有两个指针域;循环链表的特性主要表现在,在循环链表中,通过任何一个结点可以找到其他所有结点。


http://www.niftyadmin.cn/n/4819764.html

相关文章

Internet Explorer 编程简述(一)WebBrowser还是WebBrowser_V1收藏

Internet Explorer 编程简述&#xff08;一&#xff09;WebBrowser还是WebBrowser_V1收藏 新一篇: Internet Explorer 编程简述&#xff08;二&#xff09;在IE中编辑OLE嵌入文档 | 旧一篇: Internet Explorer 编程简述&#xff08;序&#xff09; <script>function Stor…

第五次个人博客 Android studio测试软件——Ui Automator测试学习及运用

在第十五周的个人博客上要求我们根据最终的团队大作业所用的软件&#xff08;Android studio&#xff09;进行软件测试的介绍&#xff0c;我选择的是基于Android自动化测试的Ui Automator安卓测试软件&#xff0c;下面我将对其进行简单的介绍。 1、UiAutomator简介 Uiautomator…

Java-MyBatis-MyBatis3-XML映射文件:XML映射文件

ylbtech-Java-MyBatis-MyBatis3-XML映射文件&#xff1a;XML映射文件1、 XML 映射文件 MyBatis 的真正强大在于它的映射语句&#xff0c;这是它的魔力所在。由于它的异常强大&#xff0c;映射器的 XML 文件就显得相对简单。如果拿它跟具有相同功能的 JDBC 代码进行对比&#xf…

Windows95/NT下OpenGL编程原理

Windows95/NT下OpenGL编程原理西安交通大学9693信箱蔡茂----科学计算可视化&#xff0c;计算机动画和虚拟现实是现在计算机图形学的三个热点。而这三个热点的核心都是三维真实感图形的绘制。由于OpenGL&#xff08;OpenGraphicsLibrary&#xff09;具有跨平台性、简便、高效、功…

WPC大会新动态: Windows Azure Platform Appliance发布

公告&#xff1a;本博客为微软云计算中文博客的镜像博客。部分文章因为博客兼容性问题&#xff0c;会影响阅读体验。如遇此情况&#xff0c;请访问原博客。 在华盛顿特区召开的 Worldwide Partner Conference (WPC)大会上&#xff0c; Bob Muglia 概述了我们对于"云"…

FAQ: 如何动态创建并访问网页元素收藏

FAQ: 如何动态创建并访问网页元素收藏 新一篇: Internet Explorer 编程简述&#xff08;十三&#xff09;调用IE隐藏的命令&#xff08;续&#xff09; | 旧一篇: Internet Explorer 编程简述&#xff08;十二&#xff09;正确地设置和转移焦点 <script>function StorePa…

Using OpenGL with MFC

[Topic] OpenGL and MFC[Viewed] 7310[Feedback] 17[Downloaded] 1941 From Francis Shanahan[.com] : http://www.francisshanahan.com/detail.aspx?cid137 This tutorial is intended to describe how to setup MFC with OpenGL or how to setup OpenGL with MFC. 请想查…

WPC大会新动态:合作伙伴采纳Windows Azure

公告&#xff1a;本博客为微软云计算中文博客的镜像博客。部分文章因为博客兼容性问题&#xff0c;会影响阅读体验。如遇此情况&#xff0c;请访问原博客。 在华盛顿特区召开的 Worldwide Partner Conference (WPC) 大会上&#xff0c;合作伙伴们履行了它们对于"云"的…