单向链表(含头尾指针)

本文主要是针对(含头尾指针)单向链表进行增、删、改、查操作

创建一个结构体当做节点
struct Node
{int iData;struct Node* pNext;
};

定义头尾指针

struct Node* pHead = NULL;
struct Node* pEnd = NULL;

pEnd指针是为了增加尾添加的效率,否则就要循环找尾

增加:1.尾添加

无(*pEnd)指针的尾添加

void AddToEndNopEnd(struct Node** pHead, struct Node** pEnd, int iData)
{//创建节点struct Node* pTemp = (struct Node*)malloc(sizeof(struct Node));if (NULL != pTemp){//节点成员赋值pTemp->iData = iData;pTemp->pNext = NULL;//链接if (NULL == *pHead){*pHead = pTemp;}else{struct Node* pt = *pHead;while (pt->pNext != NULL)     //找尾巴{pt = pt->pNext;}pt->pNext = pTemp;}}
}

有(*pEnd)指针的尾添加

void AddToEnd(struct Node** pHead, struct Node** pEnd, int iData)
{//创建节点struct Node* pTemp = (struct Node*)malloc(sizeof(struct Node));if (NULL != pTemp){//节点成员赋值pTemp->iData = iData;pTemp->pNext = NULL;//连接链表if (NULL == *pHead)//空链表{*pHead = pTemp;//*pEnd = pTemp;}else{(*pEnd)->pNext = pTemp;//*pEnd = pTemp;}*pEnd = pTemp;}
}

增加:2.头添加

void AddToHead(struct Node** pHead, struct Node** pEnd, int iData)
{//创建节点struct Node* pTemp = (struct Node*)malloc(sizeof(struct Node));if (NULL != pTemp){//节点成员赋值pTemp->iData = iData;pTemp->pNext = NULL;//连接链表if (NULL == *pHead)//空链表{//*pHead = pTemp;*pEnd = pTemp;}else{pTemp->pNext = *pHead;//*pHead = pTemp;}*pHead = pTemp;}
}

此时咱们链表的最简单的两个添加,已经完成,我们可以遍历链表来查看,并且释放链表

遍历链表
void Look(struct Node* pHead)
{while (pHead != NULL){printf("%d ", pHead->iData);pHead = pHead->pNext;}putchar('\n');
}
释放链表
void FreeList(struct Node** pHead, struct Node** pEnd)
{struct Node* pTemp = *pHead;while (pTemp != NULL){struct Node* pt = pTemp;pTemp = pTemp->pNext;free(pt);}*pHead = NULL;*pEnd = NULL;
}

释放链表记得指针要置空哈

查找:1.根据下标查询

struct Node* FindNodeByIndex(struct Node* pHead, int iIndex)
{//参数合法性检测if (NULL == pHead || iIndex < 0){printf("链表为空/位置输入有误,无法查节点\n");return NULL;}//循环链表int i = 0;while (pHead != NULL){if (i == iIndex)return pHead;i++;pHead = pHead->pNext;}printf("位置输入过大,无法查节点\n");return NULL;
}

查找:2.根据数值查询

struct Node* FindNodeByData(struct Node* pHead, int iData)
{//参数合法性检测if (NULL == pHead || iData < 0){printf("链表为空/位置输入有误,无法查节点\n");return NULL;}//循环链表while (pHead != NULL){if (pHead->iData == iData)return pHead;pHead = pHead->pNext;}return NULL;
}

升级版添加:1.在指定下标节点处添加节点

void InsertNodeByIndex(struct Node** pHead, struct Node** pEnd, int iIndex, int iData)
{//参数合法性检测if (iIndex < 0){printf("下标输入有误,请重新输入\n");return;}//下标为0,直接头添加if (0 == iIndex){AddToHead(pHead, pEnd, iData);}else{//找位置struct Node* pTemp = FindNodeByIndex(*pHead, iIndex - 1);if (pTemp != NULL){//申请节点空间struct Node* pT = (struct Node*)malloc(sizeof(struct Node));if (pT != NULL){//节点成员赋值pT->iData = iData;pT->pNext = NULL;//链接 先连后断pT->pNext = pTemp->pNext;pTemp->pNext = pT;}}else{printf("查无此节点");}}
}

升级版添加:2.在指定数值添加多个节点

看着很高大上,其实你只需要调用头添加即可,此时的头非彼头;

void AddSomeNode(struct Node** pHead, struct Node** pEnd, unsigned int iCount, unsigned int iData)
{for (unsigned int i = 0; i < iCount; i++){AddToEnd(pHead, pEnd, iData);}
}

修改:1.根据数值改变此节点数据

void ChengeData(struct Node* pHead, int iResData, int iDecData)
{struct Node* pRec = FindNodeByData(pHead, iResData);if (NULL == pRec){printf("查无此节点\n");}else{pRec->iData = iDecData;}
}

修改:2.根据数值改变此节点所有相同数据(一)

void ChengeSomeData(struct Node* pHead, int iResData, int iDecData)
{//参数合法性检测if (NULL == pHead){printf("查无此节点\n");return;}while (pHead != NULL){if (pHead->iData == iResData)pHead->iData = iDecData;pHead = pHead->pNext;}
}

修改:2.根据数值改变此节点所有相同数据(一)

void ChengeSomeDataText(struct Node* pHead, int iResData, int iDecData)
{//参数合法性检测if (NULL == pHead){printf("查无此节点\n");return;}while (FindNodeByData(pHead, iResData) != NULL){ChengeData(pHead, iResData, iDecData);}
}

删除:1.删除头结点

void DeleteHead(struct Node** pHead, struct Node** pEnd)
{//参数合法性检测if (NULL == pHead)return;if (*pHead == *pEnd || (*pHead)->pNext == NULL)//只有一个节点{free(*pHead);*pHead = NULL;*pEnd = NULL;}else{struct Node* pT = *pHead;(*pHead) = (*pHead)->pNext;free(pT);}
}

删除:2.删除尾结点

void DeleteEnd(struct Node** pHead, struct Node** pEnd)
{//参数合法性检测if (NULL == pHead)return;if (*pHead == *pEnd || (*pHead)->pNext == NULL)//只有一个节点{free(*pHead);*pHead = NULL;*pEnd = NULL;}else{//找到结尾的前一个struct Node* pT = *pHead;while (pT->pNext != *pEnd){pT = pT->pNext;}free(*pEnd);*pEnd = pT;(*pEnd)->pNext = NULL;}
}

删除:3.根据数值删除此节点(只删除一个哟)

struct Node* DeleteOneDataByData(struct Node** pHead, struct Node** pEnd, int iData)
{if (NULL == *pHead)return NULL;if ((*pHead)->iData == iData){DeleteHead(pHead, pEnd);return *pHead;}else if ((*pEnd)->iData == iData){DeleteEnd(pHead, pEnd);return *pHead;}else{//循环找节点struct Node* pTemp = *pHead;while (pTemp->pNext != NULL){if (pTemp->pNext->iData == iData)break;pTemp = pTemp->pNext;}//判断if (pTemp->pNext != NULL){struct Node* pT = pTemp->pNext; //记录pTemp->pNext = pT->pNext;free(pT);return *pHead;   //return pTemp->pNext  ----- pHead}else{printf("查无此节点\n");return NULL;}}
}

提醒一点哈,这里考虑到删除的节点可能是头结点,所有采用了返回值的方式

删除:4.根据数值删除此所有相同数据的节点

void DeleteAllDataByData(struct Node** pHead, struct Node** pEnd, int iData)
{if (NULL == *pHead)return;struct Node* pTemp = DeleteOneDataByData(pHead, pEnd, iData);while (pTemp != NULL){pTemp = DeleteOneDataByData(pHead, pEnd, iData);}
}

删除:5.根据下标删除此节点

void DeleteDataByIndex(struct Node** pHead, struct Node** pEnd, int iIndex)
{if (NULL == *pHead)return;if (0 == iIndex)DeleteHead(pHead, pEnd);else{//找前一个节点struct Node* pTemp = FindNodeByIndex(*pHead, iIndex - 1);if (pTemp != NULL){if (pTemp->pNext == *pEnd)DeleteEnd(pHead, pEnd);//记录被删除的节点struct Node* pT = pTemp->pNext;//链接pTemp->pNext = pT->pNext;//释放free(pT);}else{printf("查无此节点\n");}}
}

下面是一些其他简单操作方便大家更加熟悉链表

(1)获取节点个数

int GetListNodeCount(struct Node* pHead)
{int iCount = 0;while (NULL != pHead){iCount++;pHead = pHead->pNext;}return iCount;
}

(2)根据数值交换两个节点的数据

void SwapByData(struct Node* pHead, int iData1, int iData2)
{if (NULL == pHead)return;//查找struct Node* pT1 = FindNodeByData(pHead, iData1);struct Node* pT2 = FindNodeByData(pHead, iData2);//都找到才能交换if (pT1 != NULL && pT2 != NULL){//交换成员//struct Node p = *pT1;//*pT1 = *pT2;//*pT2 = p;//int temp = pT1->iData;//pT1->iData = pT2->iData;//pT2->iData = temp;struct Node p = *pT1;memcpy(pT1, pT2, 4);memcpy(pT2, &p, 4);}
}

(3)根据下标交换两个节点的数据

void SwapByIndex(struct Node* pHead, int iIndex1, int iIndex2)
{if (NULL == pHead)return;//查找struct Node* pT1 = FindNodeByIndex(pHead, iIndex1);struct Node* pT2 = FindNodeByIndex(pHead, iIndex2);//都找到才能交换if (pT1 != NULL && pT2 != NULL){//交换成员//int temp = pT1->iData;//pT1->iData = pT2->iData;//pT2->iData = temp;struct Node p = *pT1;memcpy(pT1, pT2, 4);memcpy(pT2, &p, 4);}
}

(4)交换指针指向节点

void SwapByChangePoint(struct Node** pHead, struct Node** pEnd, int iIndex1, int iIndex2)
{//参数合法性检测if (NULL == *pHead || NULL == (*pHead)->pNext || iIndex1 == iIndex2 || iIndex1 < 0 || iIndex2 < 0){return;}//确定大小关系int iMin = iIndex1;int iMax = iIndex2;if (iIndex1 > iIndex2){iMin = iIndex2;iMax = iIndex1;}//根据下标找节点struct Node* pMin = FindNodeByIndex(*pHead, iMin);struct Node* pMax = FindNodeByIndex(*pHead, iMax);//找不到就结束if (NULL == pMin || NULL == pMax){printf("查无此节点\n");return;}//头尾交换if (pMin == *pHead && pMax == *pEnd){if ((*pHead)->pNext == *pEnd)  //两个节点{(*pEnd)->pNext = *pHead;(*pHead)->pNext = NULL;//交换指向*pHead = *pEnd;*pEnd = (*pHead)->pNext;}else //多个节点{//找到尾巴的前一个节点struct Node* pMaxPre = FindNodeByIndex(*pHead, iMax - 1);//尾巴变头(*pEnd)->pNext = (*pHead)->pNext;//头变尾巴pMaxPre->pNext = *pHead;//头下一个为NULL(*pHead)->pNext = NULL;//交换指向*pHead = *pEnd;*pEnd = pMaxPre->pNext;}}//头和中间交换else if (pMin == *pHead && pMax != *pEnd){//相邻if (pMin->pNext == pMax){pMin->pNext = pMax->pNext;pMax->pNext = pMin;*pHead = pMax;}//不相邻else  {//找pMax的前一个指针struct Node* pMaxPre = FindNodeByIndex(*pHead, iMax - 1);//记录头的下一个节点 即链表第二个节点struct Node* pHeadNext = pMin->pNext;//头节点连在max的位置上pMin->pNext = pMax->pNext;pMaxPre->pNext = pMin;//pMax挪到头pMax->pNext = pHeadNext;//改变新的头*pHead = pMax;}}//尾和中间交换else if (pMin != *pHead && pMax == *pEnd){if (pMin->pNext == pMax)  //相邻{//找到pMin的前一个struct Node* pMinPre = FindNodeByIndex(*pHead, iMin - 1);//先把尾巴放中间pMinPre->pNext = pMax;pMax->pNext = pMin;//pMin next = NULLpMin->pNext = NULL;*pEnd = pMin;}//不相邻else{//找到pMin的前一个struct Node* pMinPre = FindNodeByIndex(*pHead, iMin - 1);//找pMax的前一个指针struct Node* pMaxPre = FindNodeByIndex(*pHead, iMax - 1);//pmax放中间去pMinPre->pNext = pMax;pMax->pNext = pMin->pNext;//pMin放尾巴上去pMaxPre->pNext = pMin;pMin->pNext = NULL;*pEnd = pMin;}}//中间两个相互交换else if (pMin != *pHead && pMax != *pEnd){//相邻if (pMin->pNext == pMax){//找到pMin的前一个节点struct Node* pMinPre = FindNodeByIndex(*pHead, iMin - 1);struct Node* pMaxNext = pMax->pNext;//将pMax装在pMin 与pMinPre中间pMinPre->pNext = pMax;pMax->pNext = pMin;//把pMax拿下来pMin->pNext = pMaxNext;}//不相邻else{//找到pMin的前一个struct Node* pMinPre = FindNodeByIndex(*pHead, iMin - 1);struct Node* pMinNext = pMin->pNext;//找pMax的前一个指针struct Node* pMaxPre = FindNodeByIndex(*pHead, iMax - 1);struct Node* pMaxNext = pMax->pNext;//将pMin撞到pMax的位置pMaxPre->pNext = pMin;pMin->pNext = pMaxNext;//将pMax撞到pMin的位置pMinPre->pNext = pMax;pMax->pNext = pMinNext;}}
}

(5)根据数据翻转链表

void ReverseByData(struct Node* pHead)
{//参数合法性检测if (NULL == pHead || NULL == pHead->pNext){return;}int iCount = GetListNodeCount(pHead);int i = 0, j = iCount - 1;for (; i < j; i++, j--){SwapByIndex(pHead, i, j);}
}

(6)根据下标翻转链表

void ReverseByPoint(struct Node** pHead, struct Node** pEnd)
{//参数合法性检测if (NULL == *pHead || NULL == (*pHead)->pNext){return;}int iCount = GetListNodeCount(*pHead);int i = 0, j = iCount - 1;for (; i < j; i++, j--){SwapByChangePoint(pHead, pEnd, i, j);}
}

此时单向链表基本操作已经完成咯~

【数据结构基础_有[*pHead]和[*pEnd]的单向链表_(C语言实现)】相关推荐

  1. c语言单向链表经典,C语言基础 - 实现单向链表

    写在前面 弄了下个人站...防止内容再次被锁定...所有东西都在这里面 welcome~ 个人博客 回归C基础 实现一个单向链表,并有逆序功能 (大学数据结构经常是这么入门的) //定义单链表结构体 ...

  2. 链表有环是什么意思_互联网大厂offer收割之单向链表的概念及面试题大全

    链表是最基本的数据结构,面试官也常常用链表来考察面试者的基本能力,而且链表相关的操作相对而言比较简单,也适合考察写代码的能力.链表的操作也离不开指针,指针又很容易导致出错.综合多方面的原因,链表题目在 ...

  3. java简单单向链表_【新手自白书】简单单项链表的实现(JAVA)

    复习一下简单单项链表的实现. 在动手写链表之前,需要思考链表是如何组成的,一般来说,一个简单的单项链表主要是由节点构成,由于链表的特性,头节点是一个十分重要的成员,所以,链表必须的成员是节点Node, ...

  4. java简单单向链表_用java简单的实现单链表的基本操作

    packagecom.tyxh.link;//节点类 public classNode {protected Node next; //指针域 protected int data;//数据域 pub ...

  5. java 链表逆序代码_如何实现一个高效的单向链表逆序输出?(详解)

    需要考虑因素,高效应权衡多方面因素 数据量是否会很大 空间是否有限制 原始链表的结构是否可以更改 时间复杂度是否有限制 一个链表节点需要输出的元素有多个,例如链表中存的是自定义对象,有多个字段 题目. ...

  6. c语言单链表功能,[数据结构]单链表(C语言)的各种功能

    06-03阅读200,000 + 链表是一种常见的基本数据结构,在此充分利用了结构指针. 链表可以动态存储和分配,即链表是一个功能非常强大的数组. 他可以在节点中定义多种数据类型,并可以根据需要随意添 ...

  7. Algorithms_基础数据结构(04)_线性表之链表_单向循环链表约瑟夫环问题

    文章目录 大纲图 链表的经典面试题目 如何设计一个LRU缓存淘汰算法 约瑟夫问题 结构 分析 大纲图 链表的经典面试题目 如何设计一个LRU缓存淘汰算法 tip:单向链表 约瑟夫问题 N个人围成一圈, ...

  8. Algorithms_基础数据结构(03)_线性表之链表_双向链表

    文章目录 大纲图 双向链表 双向链表的基本结构 双向链表的基本操作 头插 尾插 中间部位插入 删除头部 删除尾部 删除中间位置的数据 查找 更新 Code 总结 大纲图 双向链表 Algorithms ...

  9. asp子窗口读取父窗口数据_算法与数据结构基础 - 数组(Array)

    数组基础 数组是最基础的数据结构,特点是O(1)时间读取任意下标元素,经常应用于排序(Sort).双指针(Two Pointers).二分查找(Binary Search).动态规划(DP)等算法.顺 ...

  10. 在列表前方插入一个数据_通俗易懂的Redis数据结构基础教程

    Redis有5个基本数据结构,string.list.hash.set和zset.它们是日常开发中使用频率非常高应用最为广泛的数据结构,把这5个数据结构都吃透了,你就掌握了Redis应用知识的一半了. ...

最新文章

  1. 批量启用lync用户-3
  2. Tomcat下使用Druid配置JNDI数据源
  3. SQL注入——报错注入
  4. android任务 进程 线程详解,Android任务、进程、线程详解
  5. 让ie8按照ie7 的方式来进行解析
  6. 如何屏蔽LOGD\LOGI等打印输出
  7. 微信小程序开发实战——模块化
  8. SmartFoxServer 2X 安装
  9. iOS视频直播初窥:高仿喵播APP
  10. List集合排序总结
  11. 推荐一个好用的论文助手工具
  12. layui数据表格实现快捷键切换编辑单元格
  13. python-字符串格式化(万古枯)
  14. NAND Flash SLC、MLC技术解析
  15. WinCE USB驱动CDevice::EnterOperationalState函数相关
  16. 微信公共服务平台开发(.Net 的实现)13-------网页授权(下 :C#代码的实现 )
  17. 前端开发:a标签的使用
  18. js获取当前月、上一月和下一月
  19. 自动化测试之 ddt 驱动 excel 文件
  20. 大数据架构之--Kappa架构

热门文章

  1. Spring framework源码 Constants学习
  2. 图片处理工具类ImageHelper
  3. 网络爬虫案例——前程无忧网java岗位
  4. TCP 三次握手和四次挥手,中间失败了会发生什么?
  5. snaker mybatis 配置
  6. MybatisPlusException: This is impossible to happen
  7. PMP-计算题汇总(PV、EV、AC、BAC、EAC、ETC、)
  8. 707. 设计链表(中等 链表)
  9. Java程序员面试宝典——重要习题整理
  10. Firefox火狐浏览器下载