单向链表C++实现

单向链表:

从字面上理解,那就是“单向”+“链表”,表明这种数据结构是有方向性的,并且只有一个方向。另外,“链表”表明这种数据结构是一种链式存储结构,它不同于线性表的顺序存储结构。链表的相邻元素在物理内存中不连续,所以这种结构可以充分利用一些系统的内存碎片来完成一些事务,即如果采用链表结构有时可以解决当连续内存分配不足时的问题。既然是单向链表,那也意味着它是由各个元素之间通过一个指针彼此连接而组成的。每个元素包含两部分:数据域和一个称为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 <stdlib.h>
#include <stdio.h>

/* 链表数据成员的定义 */
template<typename T>
struct ListElmt
{
    T *pvData;
    struct ListElmt *pstNext;
	
};

/* 定义链表成员结构 */
template<typename T>
class List
{
public:
    List(void (*ListDestroy)(T *pData));
    ~List();
    int List_InsNext(ListElmt<T> *pstElemet, const T *pvData);
    int List_RemNext(ListElmt<T> *pstElement, T **ppvData);
    void List_Invert();
    void List_Show();
    void List_InvertedShow(ListElmt<T> *pstListElmt);
    int List_Size(){ return s32Size; }
    ListElmt<T>* List_Head(){ return pstListHead; }
    ListElmt<T>* List_Tail(){ return pstListTail; }
    int List_IsHead(ListElmt<T> *pstListElmt) {return (pstListElmt == pstListHead ? 1 : 0);}
    int List_IsTail(ListElmt<T> *pstListElmt) {return (pstListElmt == pstListTail ? 1 : 0);}
    T* List_Data(ListElmt<T> *pstListElmt){ return pstListElmt->pvData; }
    ListElmt<T>* LIST_NEXT(ListElmt<T> *pstListElmt){ return pstListElmt->pstNext;}

private:
    void (*ListDestroy)(T *pData);

public:
    int s32Size;
    ListElmt<T> *pstListHead;
    ListElmt<T> *pstListTail;
	
};

/***************************************************************
 * Function Name      : List_Init
 * Description        : 链表创建函数 
 * Param:
 *     pstList        : 创建链表所需操作集
 *     Destroy        : 链表的析构函数
 * return: 无返回值
 * Author: 
 * 日期:创建2019-08-19  修改2019-08-19
 ***************************************************************/
template<typename T>
List<T>::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<typename T>
List<T>::~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<typename T>
int List<T>::List_InsNext(ListElmt<T> *pstElemet, const T *pvData)
{
    ListElmt<T> *pstElementTmp = NULL;
    
    pstElementTmp = (ListElmt<T> *)malloc(sizeof(ListElmt<T>));
    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<typename T>
int List<T>::List_RemNext(ListElmt<T> *pstElement, T **ppvData)
{
    ListElmt<T> *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<typename T>
void List<T>::List_Show()
{
    ListElmt<T> *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<typename T>
void List<T>::List_InvertedShow(ListElmt<T> *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<typename T>
void List<T>::List_Invert()
{
    ListElmt<T> *pstListElmtTmp  = this->pstListHead;
    ListElmt<T> *pstListElmtHead = this->pstListHead;
    ListElmt<T> *pstListElmtTail = this->pstListTail;
    
    this->pstListHead = NULL;
    
    while(pstListElmtTmp)
    {
        ListElmt<T> *ptTmp = pstListElmtTmp;
 
        pstListElmtTmp = pstListElmtTmp->pstNext;              
        ptTmp->pstNext = this->pstListHead;
        this->pstListHead = ptTmp;
    }

    /* 头变成了尾 */
    this->pstListTail = pstListElmtHead;
    this->pstListHead = pstListElmtTail;
    
 }

#endif

main.cpp 代码 


#include <string.h>
#include <stdlib.h>
#include <stdio.h>
 
#include "List.h"
 
using namespace std;

/* destroy */
template<typename T>
void destroy(T *data)
{
    //printf("in destroy\n");
    free(data);
    return;
}
 
int main(int argc, char **argv)
{
    int *ps32Data = NULL;
    int i = 0;
    List<int> 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;
}

执行结果如下:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值