链表链表啦

目录

什么是链表?

链表分类

不带头的单向不循环链表 

面试题


需要的基础:结构体,动态内存管理,指针,这些要很熟。

什么是链表?

链表是一种物理上不连续,逻辑上连续的存储结构,逻辑顺序是按指针来链接的。 

 

从图知道它们物理是不连续的,一下块一小块的空间都是在堆区随机开辟的,这些空间有可能连续,也有可能不连续,通过指针连在一起。 

链表分类

1.单向与双向

2.带头与不带头(哨兵位的头节点一般存储有效数据)

 3.循环与不循环

不带头的单向不循环链表

不带头的单向不循环链表 

如何掌握它呢?那就看看以下链表的增删查改吧

#pragma once
#include<stdio.h>
#include<assert.h>
typedef int SLTDateType;
typedef struct SListNode
{
	SLTDateType data;
	struct SListNode* next;
}SListNode ;

// 动态申请一个节点
SListNode* BuySListNode(SLTDateType x);
// 单链表打印
void SListPrint(SListNode* plist);
// 单链表尾插
void SListPushBack(SListNode** pplist, SLTDateType x);
// 单链表的头插
void SListPushFront(SListNode** pplist, SLTDateType x);
// 单链表的尾删
void SListPopBack(SListNode** pplist);
// 单链表头删
void SListPopFront(SListNode** pplist);
// 单链表查找
SListNode* SListFind(SListNode* plist, SLTDateType x);
// 单链表在pos位置之后插入x
// 分析思考为什么不在pos位置之前插入?
void SListInsertAfter(SListNode* pos, SLTDateType x);
void SListInsertpre(SListNode* plist, SListNode* pos, SLTDateType x);
// 单链表删除pos位置之后的值
// 分析思考为什么不删除pos位置?
void SListEraseAfter(SListNode* pos);

// 单链表尾插
void SListPushBack(SListNode** pplist, SLTDateType x);

但这个是不是感觉很对,但是假如这个链表什么都没有呢?

讲解为什么要传二级指针

不要定性思维认为传址就可以了,而是想要改变什么就要有什么的地址

要改整型就要知道整型地址,要改结构体就要有结构体地址 ,要改一级指针就要一级指针的地址就是二级指针

void SListPushBack(SListNode** pplist, SLTDateType x)
{
	assert(pplist);

	SListNode* newnode = BuySListNode(x);
	if (*pplist == NULL)
	{
		*pplist = newnode;
	}
	else
	{
		SListNode* end = *pplist;
		while (end->next)
		{
			end = end->next;
		}
		end->next = newnode;
     }
}

 自己想想为什么要断言?

// 单链表的尾删
void SListPopBack(SListNode** pplist);

假如只有一个呢?

void SListPopBack(SListNode** pplist)
{
	assert(pplist);
	assert(*pplist);
	SListNode* end = *pplist;
	if (end->next == NULL)
	{
		free(*pplist);
		*pplist = NULL;
	}
	else
	{
		SListNode* end = *pplist;
		while (end->next->next)
		{
			end = end->next;
		}
		free(end->next);
		end->next = NULL;
	}
}

 为什么又要多一个断言呢?

总结:单链表一定考虑空指针问题,二级指针问题,断言问题

小伙伴们应该懂了吧

剩下的你们自己写了,跟上面差不多,理解好了就写的出,给我的给你们参考

void SListPrint(SListNode* plist)
{
	SListNode* cur = plist;
	while (cur)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("NULL\n");
}


SListNode* BuySListNode(SLTDateType x)
{
	SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return NULL;
	}
	newnode->data = x;
	newnode->next = NULL;
	return newnode;
}

void SListPushBack(SListNode** pplist, SLTDateType x)
{
	assert(pplist);

	SListNode* newnode = BuySListNode(x);
	if (*pplist == NULL)
	{
		*pplist = newnode;
	}
	else
	{
		SListNode* end = *pplist;
		while (end->next)
		{
			end = end->next;
		}
		end->next = newnode;
     }
}

void SListPopBack(SListNode** pplist)
{
	assert(pplist);
	assert(*pplist);
	SListNode* end = *pplist;
	if (end->next == NULL)
	{
		free(*pplist);
		*pplist = NULL;
	}
	else
	{
		SListNode* end = *pplist;
		while (end->next->next)
		{
			end = end->next;
		}
		free(end->next);
		end->next = NULL;
	}
}

void SListPushFront(SListNode** pplist, SLTDateType x)
{
	assert(pplist);

	SListNode* newnode = BuySListNode(x);

	if (*pplist == NULL)
	{
		*pplist = newnode;
	}
	else
	{
		newnode->next = *pplist;
		*pplist = newnode;
	}
}

void SListPopFront(SListNode** pplist)
{
	assert(*pplist);
	assert(pplist);

	SListNode* star = *pplist;
	*pplist = star->next;
	free(star);
}
SListNode* SListFind(SListNode* plist, SLTDateType x)
{
	SListNode* cur = plist;
	while (cur->next)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

void SListInsertAfter(SListNode* pos, SLTDateType x)
{
	assert(pos);
	SListNode* newnode = BuySListNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}

void SListInsertpre(SListNode** pplist, SListNode* pos, SLTDateType x)
{
	assert(pos);
	assert(pplist);
	//assert(*pplist);
	/*SListNode* cur = *pplist;*/
	SListNode* newnode = BuySListNode(x);
	if (*pplist ==pos)
	{
		newnode->next = pos;
		*pplist = newnode;
	}
	else
	{
		SListNode* cur = *pplist;
		while (cur->next != pos)
		{
			cur = cur->next;
		}
		cur->next = newnode;
		newnode->next = pos;
	}
}

void SListEraseAfter(SListNode* pos)
{
	assert(pos);
	assert(pos->next);
	SListNode* cur=pos->next;
	pos->next =cur-> next;
	free(cur);

}


面试题

1

思路:头插,一个一个插进新的链表

反转链表备战技术面试?力扣提供海量技术面试资源,帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。icon-default.png?t=N7T8https://leetcode.cn/problems/reverse-linked-list/description/

struct ListNode* reverseList(struct ListNode* head) 
{
    if(head==NULL)
    return NULL;
    struct ListNode* rhead=NULL;
    struct ListNode* cur=head;
    struct ListNode* afcur=head->next;
    while(cur)
    {
        cur->next=rhead;
        rhead=cur;
        cur=afcur;
        
        if(afcur)
        afcur=afcur->next;
    }
    return rhead;
}

2. 链表中倒数第k个结点_牛客题霸_牛客网

思路:快慢指针问题,给一个快指针,一个慢指针,快指针先走k步,然后同时走,快指针是NULL 时停,你们可以试试写不写的出

struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
    struct ListNode* fast=pListHead;
    struct ListNode* slow=pListHead;
    for(int i=0;i<k;i++)
    {
        if(fast==NULL)
        return NULL;
        fast=fast->next;
    }
    while(fast)
    {
        slow=slow->next;
        fast=fast->next;
    }
    return slow;
}

3. 环形链表I备战技术面试?力扣提供海量技术面试资源,帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。icon-default.png?t=N7T8https://leetcode.cn/problems/linked-list-cycle/

思路:快慢指针,快指针走2步,慢指针走一步,假如有环,快指针先进环,然后慢指针追赶,一定能追上,最后两个指针指向同一个位置。

bool hasCycle(struct ListNode* head) {
    struct ListNode* fast=head;
    struct ListNode* slow=head;
    while(fast&&fast->next)
    {
        
        fast=fast->next->next;
        slow=slow->next;
        if(fast==slow)
        {
            return true;
        }
        
    }
    return false;
}

 解释:为什么快指针要走2步,三步行不行呢?

所以说fast走一步肯定能相遇

3.环形链表II备战技术面试?力扣提供海量技术面试资源,帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。icon-default.png?t=N7T8https://leetcode.cn/problems/linked-list-cycle-ii/description/

思路:一个指针从头开始走,一个指针从相遇点开始走,当两个指针相等时的位置就是环开始的位置。是有点难想到并且也难理解,后面有解释。

struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode* fast=head;
    struct ListNode* slow=head;
    while(fast&&fast->next)
    {
        
        fast=fast->next->next;
        slow=slow->next;
        if(fast==slow)
        {
            struct ListNode* meet=fast;
            struct ListNode* newnode=head;
            while(meet!=newnode)
            {
                meet=meet->next;
                newnode=newnode->next;
            }
            return meet;
        }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奇点 ♡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值