数据结构:单链表功能实现及面试题整理

序:

调用函数时,其实就是把变量的地址传给函数,但是函数只能修改指针指向变量的值,不能修改指针的指向

如果需要修改指针的指向就必须在传参时传指针的指针!

比如:单链表在遍历,查找时就不需要改变指针指向,插入删除就必须改变指针指向

为了保证代码质量,我将所有的函数都使用指针的指针形式

先附上运行结果:

ListNode.h

#pragma once

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

typedef int DataType;

typedef struct ListNode
{
	struct ListNode* _pnext;
	DataType _pdata;
}Node,*pNode;

void SListInit(pNode* pHead);
void PrintList(pNode* pHead);
pNode BuySListNode(DataType data);
void SListPushBack(pNode* pHead,DataType data);
void SListPopBack(pNode* pHead);
void SListPushFront(pNode* pHeaf,DataType data);
void SListPopFront(pNode* pHead);
void SListInsert(pNode* pHead,pNode pos,DataType data);
int SListEmpty(pNode* pHead);
int SListSize(pNode* pHead,DataType data);
void SListErase(pNode* pHead,pNode pos);
pNode SListFind(pNode* pHead,DataType data);
void SListDestroy(pNode* pHead);

ListNode.c

#include"ListNode.h"

void SListInit(pNode* pHead)
{
	assert(pHead);
	*pHead = NULL;
}
void PrintList(pNode* pHead)
{
	pNode pCur = *pHead;
	if (pCur == NULL)
	{
		printf("链表为空\n");
		return;
	}
	while (pCur)
	{
		printf("%d->",pCur->_pdata);
		pCur = pCur->_pnext;
	}
	printf("NULL\n");

}
pNode BuySListNode(DataType data)
{
	pNode pNewNode = (pNode)malloc(sizeof(Node));
	if (NULL == pNewNode)
	{
		perror("pNewNode");//perror ( )用 来 将 上 一 个 函 数 发 生 错 误 的 原 因 输 出 到 标 准 错误 (stderr)
		                   //在库函数中有个error变量,每个error值对应着以字符串表示的错误类型。当你调用"某些"函数出错时,该函数已经重新设置了error的值。perror函数只是将你输入的一些信息和现在的error所对应的错误一起输出。
		exit(EXIT_FAILURE);//退出,stdlib.h中定义了#define EXIT_FAILURE 1
		                   //可以用做exit()的参数来使用,表示没有成功的执行一个程序
		//assert(0);         0为假,打印一条错误信息,然后停止程序运行

		//return NULL;       返回为空。
	}
	pNewNode->_pdata = data;
	pNewNode->_pnext = NULL;
	return pNewNode;
}

void SListPushBack(pNode* pHead, DataType data)
{
	pNode pCur = *pHead;
	assert(pHead);
	if (NULL == pCur)
	{
		*pHead = BuySListNode(data); //如果链表为空,直接插
	}
	else                            //链表不为空时,找到最后一个再插入
	{
		while (pCur->_pnext)
		{
			pCur = pCur->_pnext;    //循环直到pCur->_pnext为空,找到最后一个
		}
		pCur->_pnext = BuySListNode(data);
	}
}

void SListPopBack(pNode* pHead)
{
	pNode pCur = *pHead;
	pNode pTail = NULL;
	assert(pHead);
	if (NULL == *pHead)//头结点不存在
	{
		return;
	}
	else if (NULL == (*pHead)->_pnext)//只有一个节点
	{
		free(*pHead);
		*pHead = NULL;
	}
	else//节点超过一个
	{
		while (pCur->_pnext)//pCur->_pnext循环直到指向NULL,pCur同时找到最后一个节点,pTail找到倒数第二个接点
		{
			pTail = pCur;
			pCur = pCur->_pnext;
		}
		pTail->_pnext = NULL;
     	free(pCur);
		pCur = NULL;
	}

}
void SListPushFront(pNode* pHead, DataType data)
{
	pNode pNewNode = BuySListNode(data);
	assert(pHead);

	pNewNode->_pnext = *pHead;
	*pHead = pNewNode;
}
void SListPopFront(pNode* pHead)
{
	pNode pDelNode = *pHead;
	if (NULL == *pHead)
	{
		assert(pHead);
		return;
	}
	else
	{
		*pHead = pDelNode->_pnext;
		free(pDelNode);

	}
}

void SListInsert(pNode* pHead, pNode pos, DataType data)//将值为data的节点插入pos的后面
{
	pNode pNewNode = NULL;
	if (NULL == pHead || NULL == pos)
	{
		printf("链表不存在\n");
		return;
	}
	else
	{
		pNewNode = BuySListNode(data);
		pNewNode->_pnext = pos->_pnext;
		pos->_pnext = pNewNode;
	}

}
int SListEmpty(pNode* pHead)
{
	if (NULL == pHead)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}
int SListSize(pNode* pHead, DataType data)//找到值为data的节点个数
{
	int count = 0;
	pNode pCur = *pHead;
	if (NULL == pHead)
	{
		printf("链表为空\n");
		return 0;
	}
	while (pCur)
	{
		if (pCur->_pdata == data)
		{
			count++;
		}
		pCur = pCur->_pnext;
	}
	return count;
}
void SListErase(pNode* pHead, pNode pos)
{
	pNode pDel = NULL;
	assert(pHead);
	if (pHead == NULL || NULL == pos)
	{
		printf("输入错误\n");
		return;
	}
	else
	{
		pDel = pos->_pnext;
		pos->_pdata = pDel->_pdata;//交换pos和pDel的data
		pos->_pnext = pDel->_pnext;//删除pDel
		free(pDel);
		pDel = NULL;
	}
}
pNode SListFind(pNode* pHead, DataType data)
{
	pNode pCur = *pHead;
	if (NULL == pHead)
	{
		printf("链表为空\n");
		return NULL;
	}
	while (pCur)
	{
		pCur = pCur->_pnext;
		if (pCur->_pdata == data)
		{
			return pCur;
		}
	}
	return NULL;
}
void SListDestroy(pNode* pHead)
{
	pNode pCur = *pHead;
	pNode pnext = NULL;
	assert(pHead);
	if (NULL == pHead)
	{
		return;
	}
	else
	{
		*pHead = NULL;
		while (pCur)
		{
			pnext = pCur->_pnext;
			free(pCur);
			pCur = pnext;
		}
	}
}


test.c

#include"ListNode.h"
int main()
{
	pNode Slist,pos;
	SListInit(&Slist);
	printf("初始化之后的链表为: ");
	PrintList(&Slist);

	SListPushBack(&Slist, 1);
	SListPushBack(&Slist, 2);
	SListPushBack(&Slist, 3);
	SListPushBack(&Slist, 4);
	SListPushBack(&Slist, 5);
	SListPushBack(&Slist, 6);
	printf("尾插之后的链表为:");
	PrintList(&Slist);

	SListPopBack(&Slist);
	printf("尾删后的链表为: ");
	PrintList(&Slist);

	SListPushFront(&Slist, 0);
	printf("头插后的链表为: ");
	PrintList(&Slist);

	SListPopFront(&Slist);
	printf("头删后的链表为: ");
	PrintList(&Slist);

	printf("寻找节点为3的个数:%d\n", SListSize(&Slist, 3));

	pos = SListFind(&Slist,3);//pos为节点,通过Find的=函数返回一个节点进行传参
	SListInsert(&Slist,pos,9);
    printf("在节点为3的位置后插入9:\n");
	PrintList(&Slist);

    SListErase(&Slist,pos);
	printf("删除值为3的节点:\n");
	PrintList(&Slist);

	system("pause");
	return 0;
}

单链表面试题思路

  • 0、删除单链表p指向的那个元素,(时间和空间复杂度尽量小)
    为了时间和空间复杂度尽量小,尽可能不改变链表本身结构。
    将q的值赋给节点p在将p节点删除
  • 1、找出单链表的倒数第K个元素,(仅允许遍历一遍链表)
    快慢指针,倒数第K个,所以快指针比慢指针先走K步,当快指针到尾部是,慢指针距尾部K个元素
  • 2、找出单链表的中间元素,(仅允许遍历一遍链表)
    快慢指针,fast走两步,slow走一步,fast走到尾部是slow正好的中间
  • 3、判断单链表是否有环(6形状)?
    快慢指针,快指针走两步,慢指针走一步,若有环,快指针总会追上慢指针,如果不会环,快指针遇见NULL接受
  • 4、如何找到环的入口?
    设起始位置到入口位置长度为L,相遇点距入口点为S,
    相遇时,慢指针:L+S 快指针领先n圈:L+S+nR,快指针是慢指针两倍速度:2(L+S)=L+S+nR
    化简:L=nR-S
    L仍然表示从链表头到达环入口的距离,而nR−S可以看成从起始点出发移动nR步后再倒退S步
    即两个指针一个从起始位置开始,一个从相遇点开始,每次走一步,再次相遇时为如入口点!
  • 5、如何知道环的长度?
    记录某一定点,相遇点或者入口点,一个指针不动,另一个一直走,再次相遇是为一圈,记录所走过的长度
  • 6、带环链表的长度是多少?
    带环链表的长度为L+R(起始位到入口点的长度和环长度)
  • 7、如何知道两个单链表(无环)是否相交
    1:因为是单链表,所以如果有相交结果必定为Y型,使用两个指针向后走,如果尾节点相同则为相交
    2:人为构环,将尾部连接到b首,指针在a中移动,如果出现在b环中则为相交
  • 8、如果两个单链表(无环)相交,如何知道它们相交的第一个节点是什么
    由于单链表相交肯定是Y型,所以如果有长度差别肯定在相交之前,遍历ab两链表,求出长度差
    快指针先走长度差步,慢指针在走,两指针速度相同,相遇即为第一个节点
  • 9、如何知道两个单链表(有环)是否相交
    两个单链表有环相交时,环为共用环,求出a的入口点,判断入口点是否在b环上
    或判断出a的快慢指针交点,看其是否在b上
  • 10、单链表实现约瑟夫环
    pNode JosephCycle(pNode* pHead, DataType m)
    {
    	assert(pHead);
    	pNode pcur = *pHead;
    	if (pcur)
    		return 0;
    	while (1)
    	{
    		if (pcur->next == pcur)
    			return pcur;
    		int c = m;
    		while (--c)
    		{
    			pcur = pcur->next;
    		}
    		pNode del = pcur->next;
    		pcur->date = del->date;
    		pcur->next = del->next;
    		free(del);
    		del = NULL;
    	}
    }

     
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值