单向链表:
从字面上理解,那就是“单向”+“链表”,表明这种数据结构是有方向性的,并且只有一个方向。另外,“链表”表明这种数据结构是一种链式存储结构,它不同于线性表的顺序存储结构。链表的相邻元素在物理内存中不连续,所以这种结构可以充分利用一些系统的内存碎片来完成一些事务,即如果采用链表结构有时可以解决当连续内存分配不足时的问题。既然是单向链表,那也意味着它是由各个元素之间通过一个指针彼此连接而组成的。每个元素包含两部分:数据域和一个称为next的指针域。通过采用这种结构,next的指针域将按某一个方向指向其下一个元素。最后一个元素的next指针域指向NULL,即为空,它表示链表的末尾元素,链表的第一个元素称为“头”元素。链表的示意图如下所示:
如上图所示,每个元素链接在一起形成一个链表。
单向链表的一个特性就是只能沿着next指针的方向寻找到其后续元素,如果要寻找到链表中的某个元素,只能从头到尾遍历整个链表。如果我们已经从头到尾访问到某个元素,但是此时又想访问这个元素的前几个元素,此时我们是无法进行访问,因为在我们的元素中并没有维护一个前向的链接,所以此时必须再次从头进行遍历操作才行。
简单回顾完单向链表的基本知识点后,下面我们要真枪实弹的开练了。以下是具体的代码,它包含三个部分,先对每个部分进行简单的描述说明:
list.h -->主要是单向链表的一些接口定义(使用C++ 模板类实现)
main.cpp -->主要是展示链表的一些简单应用
list.h代码如下:
/**************************************************************************
* *
* Copyright (c) 2018, yangxuejian *
* ALL RIGHTS RESERVED. *
* Author: *
* Time : 2018-03-29 16:36:12 *
* *
**************************************************************************/
#ifndef _LIST_HH
#define _LIST_HH
#include
#include
/* 链表数据成员的定义 */
template
struct ListElmt
{
T *pvData;
struct ListElmt *pstNext;
};
/* 定义链表成员结构 */
template
class List
{
public:
List(void (*ListDestroy)(T *pData));
~List();
int List_InsNext(ListElmt *pstElemet, const T *pvData);
int List_RemNext(ListElmt *pstElement, T **ppvData);
void List_Invert();
void List_Show();
void List_InvertedShow(ListElmt *pstListElmt);
int List_Size(){ return s32Size; }
ListElmt* List_Head(){ return pstListHead; }
ListElmt* List_Tail(){ return pstListTail; }
int List_IsHead(ListElmt *pstListElmt) {return (pstListElmt == pstListHead ? 1 : 0);}
int List_IsTail(ListElmt *pstListElmt) {return (pstListElmt == pstListTail ? 1 : 0);}
T* List_Data(ListElmt *pstListElmt){ return pstListElmt->pvData; }
ListElmt* LIST_NEXT(ListElmt *pstListElmt){ return pstListElmt->pstNext;}
private:
void (*ListDestroy)(T *pData);
public:
int s32Size;
ListElmt *pstListHead;
ListElmt *pstListTail;
};
/***************************************************************
* Function Name : List_Init
* Description : 链表创建函数
* Param:
* pstList : 创建链表所需操作集
* Destroy : 链表的析构函数
* return: 无返回值
* Author:
* 日期:创建2019-08-19 修改2019-08-19
***************************************************************/
template
List::List(void (*ListDestroy)(T *pData))
{
this->pstListHead = NULL;
this->pstListTail = NULL;
this->ListDestroy = ListDestroy;
this->s32Size = 0;
}
/***************************************************************
* Function Name : List_Destroy
* Description : 链表销毁函数
* Param:
* pstList : 销毁链表所需操作集
* return: 无返回值
* Author:
* 日期:创建2019-08-19 修改2019-08-19
***************************************************************/
template
List::~List()
{
T *pData;
/* 删除所有的节点 */
while(List_Size() > 0)
{
if(List_RemNext(NULL, (T **)&pData) == 0 && ListDestroy != NULL)
{
ListDestroy(pData);
this->s32Size--;
}
}
/* 清空链表数据集 */
this->pstListHead = NULL;
this->pstListTail = NULL;
this->ListDestroy = NULL;
return;
}
/***************************************************************
* Function Name : List_InsNext
* Description : 链表节点插入成员
* Param:
* pstList : 链表所需操作集
* pstElemet : 在此节点后面插入一个节点,(若为NULL 则在头节点之前插入节点)
* pvData : 插入的真正的数据
* return: 0 成功 其他失败
* Author:
* 日期:创建2019-08-19 修改2019-08-19
***************************************************************/
template
int List::List_InsNext(ListElmt *pstElemet, const T *pvData)
{
ListElmt *pstElementTmp = NULL;
pstElementTmp = (ListElmt *)malloc(sizeof(ListElmt));
if(pstElementTmp == NULL)
return -1;
pstElementTmp->pvData = (T *)pvData;
if(pstElemet == NULL)
{
/* 头部插入节点 */
if(List_Size() == 0)
this->pstListTail = pstElementTmp;
pstElementTmp->pstNext = this->pstListHead;
this->pstListHead = pstElementTmp;
}
else
{
/* 在节点pstElement 后面插入节点 */
if( pstElemet->pstNext == NULL )
this->pstListTail = pstElementTmp; /* 更新尾节点 */
pstElementTmp->pstNext = pstElemet->pstNext;
pstElemet->pstNext = pstElementTmp;
}
/* 增加节点计数 */
this->s32Size++;
return 0;
}
/***************************************************************
* Function Name : List_RemNext
* Description : 链表节点删除成员
* Param:
* pstList : 销毁链表所需操作集
* pstElemet : 在此节点后面删除一个节点,(若为NULL 则在头节点之前插入节点)
* pvData : 插入的真正的数据
* return: 0 成功 其他失败
* Author:
* 日期:创建2019-08-19 修改2019-08-19
***************************************************************/
template
int List::List_RemNext(ListElmt *pstElement, T **ppvData)
{
ListElmt *pstElementTmp;
/* 1. 判断单项链表是否为空 */
if( List_Size() == 0 )
return -1;
/* 2. 判断是否从头节点删除成员 */
if( pstElement == NULL )
{
/* 删除头节点 */
*ppvData = this->pstListHead->pvData; /* 保存要删除的节点的数据块 */
pstElementTmp = this->pstListHead;
this->pstListHead = this->pstListHead->pstNext;
if(List_Size() == 1)
this->pstListTail = NULL;
}
else
{
/* 如果该节点的下一个节点为空则返回 */
if(pstElement->pstNext == NULL)
return -1;
*ppvData = pstElement->pstNext->pvData;
pstElementTmp = pstElement->pstNext;
pstElement->pstNext = pstElement->pstNext->pstNext;
if(pstElement->pstNext == NULL) //be care to the tail
this->pstListTail = pstElement;
}
free(pstElementTmp);
this->s32Size--;
return 0;
}
/***************************************************************
* Function Name : List_Show
* Description : 正序显示所有的成员数据块
* Param:
* pstList : 链表所需操作集
* eDataType : 要操作的数据类型
* return: 0 成功 其他失败
* Author:
* 日期:创建2019-08-19 修改2019-08-19
***************************************************************/
template
void List::List_Show()
{
ListElmt *pstListElmtTmp = pstListHead;
while(pstListElmtTmp)
{
printf("%d ", *(int *)pstListElmtTmp->pvData);
pstListElmtTmp = pstListElmtTmp->pstNext;
}
}
/***************************************************************
* Function Name : List_InvertedShow
* Description : 倒序显示所有的成员数据块
* Param:
* pstList : 链表所需操作集
* return: 0 成功 其他失败
* Author: 杨雪俭
* 日期:创建2019-08-19 修改2019-08-19
***************************************************************/
template
void List::List_InvertedShow(ListElmt *pstListElmt)
{
if(pstListElmt->pstNext != NULL)
{
List_InvertedShow(pstListElmt->pstNext);
}
printf("%d ", *(int *)pstListElmt->pvData);
}
/***************************************************************
* Function Name : List_Invert
* Description : 链表的倒叙算法
* Param:
* pstList : 链表所需操作集
* return: 0 成功 其他失败
* Author:
* 日期:创建2019-08-19 修改2019-08-19
***************************************************************/
template
void List::List_Invert()
{
ListElmt *pstListElmtTmp = this->pstListHead;
ListElmt *pstListElmtHead = this->pstListHead;
ListElmt *pstListElmtTail = this->pstListTail;
this->pstListHead = NULL;
while(pstListElmtTmp)
{
ListElmt *ptTmp = pstListElmtTmp;
pstListElmtTmp = pstListElmtTmp->pstNext;
ptTmp->pstNext = this->pstListHead;
this->pstListHead = ptTmp;
}
/* 头变成了尾 */
this->pstListTail = pstListElmtHead;
this->pstListHead = pstListElmtTail;
}
#endif
main.cpp 代码
#include
#include
#include
#include "List.h"
using namespace std;
/* destroy */
template
void destroy(T *data)
{
//printf("in destroy\n");
free(data);
return;
}
int main(int argc, char **argv)
{
int *ps32Data = NULL;
int i = 0;
List List_exp(destroy);
printf("\ncreate a list:\n");
for(i = 0; i < 10; i++ )
{
ps32Data = (int *)malloc(sizeof(int));
if( ps32Data == NULL )
return -1;
*ps32Data = i;
List_exp.List_InsNext(List_exp.pstListTail, ps32Data);
}
List_exp.List_Show();
printf("\n");
List_exp.List_InvertedShow(List_exp.pstListHead);
List_exp.List_Invert();
printf("after invertList:\n");
List_exp.List_InvertedShow(List_exp.pstListHead);
printf("\n");
List_exp.List_Show();
printf("list size : %d\n", List_exp.List_Size());
return 0;
}
执行结果如下: