链表

      通常对于链表,我们可以定义为一种链式存储的线性表,用一组地址任意的存储单元存放线性表的数据元素,称存储单元为一个结点。
      首先,我定义了一个有关链表结点的结构体,其中包括一个储存于当前链表结点的元素data和一个指向下一个结点的结构体指针next。代码如下:

typedef   int DataType;

typedef struct ListNode{
    DataType data;
    struct  ListNode *next;
} ListNode;

             对于链表中结点的创建,链表的初始化和销毁的定义,代码如下:

//创建结点
static ListNode *CreateNode(DataType  data)
{
    ListNode *newNode = (ListNode*)malloc(sizeof(ListNode));
    assert(newNode);
    newNode->data = data;
    newNode->next = NULL;
    return newNode;
}
//初始化
void  ListInit(ListNode **ppfirst)
{
    assert(ppfirst != NULL);
    *ppfirst = NULL;
}
//销毁
void ListDestory(ListNode **ppfirst)
{
    *ppfirst = NULL;
}

             完成这些操作后,下面将叙述有关链表的插入,删除和查找等相关知识。首先叙述有关链表的查找。

             对于一个链表的查找,应当循环遍历整个链表,如果链表中有结点匹配到到查找的元素data,将其返回,否则返回NULL。代码如下:

//查找
ListNode   *ListFind(ListNode *first, DataType data)
{
    for (ListNode *cur = first; cur != NULL; cur = cur->next)
    {
        if (data == cur->data)
            return cur;
    }
    return NULL;
}

        接下来叙述对于有关链表的的插入,链表的插入基本可以分为头插,尾插,指定结点前插入三种情况,下面将一一列举:
       1.头插,代码如下:

//头插
void   ListPushFront(ListNode **ppfirst, DataType data)
{
    assert(ppfirst != NULL);
    //正常情况
    //指针ppfirst指向头结点,从堆上申请空间
    ListNode *newNode = CreateNode(data);
    newNode->next = *ppfirst;

    *ppfirst = newNode;
}

             2.尾插,当链表为空时,直接插入。如果链表不为空,应当循环遍历整个链表找到最后一个结点,然后在其尾部做插入即可。代码如下:


//尾插
void    ListPushBack(ListNode **ppfirst, DataType data)
{
	ListNode *newNode = CreateNode(data);
	//特殊情况,找到倒数第一个(至少有一个,特殊情况是链表为空)
	if (*ppfirst == NULL)
	{
		*ppfirst = newNode;
		return;
	}
	//通常情况
	ListNode *cur = *ppfirst;
	while (cur->next != NULL)
	{
		cur = cur->next;
	}
	cur->next = newNode;
}

            3.在一个结点前插入,首先定义一个指针pos标记指定结点。如果pos是头结点,直接做头插即可。否则,循环遍历整个链表并找到pos前一个结点,然后在它们中间插入即可。相关代码如下:

//在结点前做插入(结点pos肯定在链表中&&pos不是空)
void   ListInsert(ListNode **ppfirst, ListNode *pos, DataType data)
{
    //头插
    if (*ppfirst==pos)
    {
        ListPushFront(ppfirst, data);
        return;
    }
    ListNode *cur = *ppfirst;
    //找到pos前一个结点
    while (cur->next != pos)
    {
        cur = cur->next;
    }
    //插入新结点
    ListNode *newNode = CreateNode(data);
    newNode->next = cur-> next;
    cur->next = newNode;

}

           同样对于一个链表的的删除,也基本可以分为头删,尾删,删除指定结点三种情况,下面也将一一列举:
          1.头删,首先应确保指向链表头结点的指针变量地址有效,并且链表不为空的情况下,才能做删除。相关代码如下:

//头删
void   ListPopFront(ListNode **ppfirst)
{
    assert(ppfirst != NULL);//变量地址不为NULL
    assert(*ppfirst != NULL);//不能是空链表

    ListNode *del = *ppfirst;
    *ppfirst = del->next;
   //重点
    free(del);
}

              2.尾删,同样得确保确保指向链表头结点的指针变量地址有效,并且链表不为空。当链表中有只有一个结点,直接删除。否则,循环遍历整个链表找到并找到最后一个节点,然后删除。代码如下:

//尾删
void  ListPopBack(ListNode **ppfirst)
{
    assert(ppfirst != NULL);//变量地址不为NULL
    assert(*ppfirst != NULL);//不能是空链表
    //链表中只有一个结点
    if ((*ppfirst)->next == NULL)
    {
        free(*ppfirst);
        *ppfirst = NULL;
        return;
    }
    //正常情况
    ListNode  *del;
    ListNode  *cur = *ppfirst;

    while (cur->next->next != NULL)
    {
        cur = cur->next;
    }
    del = cur->next;
    cur->next = NULL;
    free(del);
}

             3.删除指定的结点,与指定结点前插入一样,应当定义一个指针pos标记指定结点。当pos是头结点,直接做头删。否则,循环遍历整个链表找到pos这个结点,然后删除即可。代码如下:

//删除指定结点(结点pos肯定在链表中&&pos不是空)
void  ListErase(ListNode **ppfirst, ListNode *pos)
{
    //头删
    if (*ppfirst == pos)
    {
        ListPopFront(ppfirst);
        return;
    }
    ListNode *cur = *ppfirst;
    //找到pos前一个结点
    while (cur->next != pos)
    {
        cur = cur->next;
    }
    cur->next = pos->next;
    free(pos);
}

 

   


 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值