C语言实现单链表面试题(基础篇)

C语言实现单链表面试题(基础篇)

1.比较顺序表和链表的优缺点,说说它们分别在什么场景下使用?

顺序表:

(1)内存中地址连续

(2)支持随机查找,类似于数组用下标查找

(3)适用于需要大量访问元素而很少增加或者删除元素的程序

链表:

(1)内存中地址不连续

(2)不支持随机查找

(3)适用于需要进行大量的增加或者删除而很少查找的程序

先定义一个单链表:

 

#include<stdio.h>
typedef int DataType;
typedef struct ListNode
{
	DataType data;
	struct Node* next;
}Node,*pNode,*pList;

 

2.逆序打印单链表

思路:这里采用递归实现逆序打印,一直递归到最后一个,然后打印出来,返回上一层,这就实现了逆序打印。

具体代码如下:

 

//逆序打印单链表
void ReversePrint(pList plist)
{
    pNode cur = plist;
    if(cur == NULL)
    {
        return;
    }
    else if(cur->next == NULL)
    {
        printf("%d",cur->data);
        return;
    }
    else
    {
        ReversePrint(cur->next);//递归调用
        printf("%d",cur->data);
    }
}

 

3.删除一个无头单链表的非尾节点 

思路:删除无头单链表的非尾节点,也就是不删除尾,我们就要判断不为尾节点再删除;交换当前节点和下一个节点的值,释放掉下一个节点。

具体代码如下:

//删除无头单链表的非尾节点
void EraseNotTail(pNode pos)
{
    pNode del = pos->next;
    assert(pos->next != NULL);
    //数据替换删除
    pos->data = pos->next->data;
    pos->next = pos->next->next;
    free(del);
}

 

4.在无头单链表的一个节点前插入一个节点 

思路:在当前节点后面插入一个节点,交换插入的节点与当前节点的数据。

具体代码如下:

//在当前节点前插入一个数据x
void InsertFrontNode(pNode pos,DataType d)
{
    pNode NewNode = BuyNode(d);
    pNode tmp = NULL;
    pNode cur = pos;
    NewNode->next = pos->next;
    cur->next = NewNode;
    //数据交换
    tmp = cur->data;
    cur->data = NewNode->data;
    NewNode->data = tmp;
}

5.单链表实现约瑟夫环

思路:每次数到num的时候删除该节点,直到最后只剩下一个节点,并返回该节点。

具体代码如下:

//约瑟夫环
pNode JosephCycle(pList* pplist,int num)
{
    pNode cur = *pplist;
    assert(pplist);
    while(1)
    {
        int i = 0;
        pNode del = NULL;
        if(cur->next == cur)
        {
            break;
        }
        for(i=0;i<num-1;i++)
        {
            cur = cur->next;
        }
        printf("%d\n",cur->data);
        del = cur->next;
        cur->data = cur->next->data;
        cur->next = cur->next->next;
        free(del);
    }
    return cur;
}

6.逆置/反转单链表 

思路:创建一个新的头指针,用cur和tmp摘节点进行头插,每次把链表的头结点指向新的头结点。

具体代码如下:

//链表的逆序
void ReverseList(pList* pplist)
{
    pList NewList = NULL;
    pNode cur = *pplist;
    assert(pplist);
    //空链表或者一个节点不用逆序
    if((*pplist == NULL) || ((*pplist)->next == NULL))
    {
        return;
    }
    //
    while(cur)
    {
        pNode tmp = cur;
        cur = cur->next;
        tmp->next = NewList;
        NewList = tmp;
    }
    *pplist = NewList;
}

 

7.单链表排序(冒泡排序&快速排序) 

思路:用cur和next控制,用tail标记链表尾部,符合条件则交换,当next走到tail时第一趟结束,然后重复上述过程。

具体代码如下:

 

//排序链表(冒泡)
void BubbleSort(pList* pplist)
{
    pNode cur = *pplist;
    pNode tail = NULL;
    assert(pplist);
    if((cur == NULL) || (cur->next == NULL))
    {
        return;
    }
    while(cur->next != tail)
    {
        while(cur->next != tail)
        {
            if(cur->data > cur->next->data)
            {
                DataType tmp = cur->data;
                cur->data = cur->next->data;
                cur->next->data = tmp;
            }
            cur = cur->next;
        }
        tail = cur;
        cur = *pplist;
    }
}

 

8.合并两个有序链表,合并后依然有序 

思路:定义一个新的头指针,一开始指向pList1和pList2首元素较小的那个,然后依次遍历两个链表,每次把较小的那个值加到新头指针List的后面。

具体代码如下:

 

//合并两个有序的链表
pList Merge(pList l1,pList l2)
{
	pList myList = NULL;
	pNode tail = NULL;
	if(l1 == l2)
	{
		return l1;
	}
	if(l1 == NULL)
	{
		return l2;
	}
	if(l2 == NULL)
	{
		return l1;
	}
	//确定第一个节点
	if(l1->data <= l2->data)
	{
		myList = l1;
		l1 = l1->next;
	}
	else
	{
		myList = l2;
		l2 = l2->next;
	}
	//把尾指针赋值
	tail = myList;
	while((l1 != NULL)&&(l2 != NULL))
	{
		if(l1->data <= l2->data)
		{
			tail->next = l1;
			tail = l1;
			l1 = l1->next;
		}
		else
		{
			tail->next = l2;
			tail = l2;
			l2 = l2->next;
		}
	}
	//有一条为空了
		if(l1 == NULL)
		{
			tail->next = l2;
		}
		else
		{
			tail->next = l1;
		}
		return myList;
}


9.查找单链表的中间节点,要求只能遍历一次链表 

 

思路:快慢针指,每次快指针走两步,慢指针走一步;

(1)链表有奇数个节点,快指针走到结尾时慢指针刚好走到中间。

(2)链表有偶数个节点,快指针指向空,慢指针走到链表中间。

具体代码如下:

 

//查找中间节点
pNode FindMidNode(pList plist)//快慢指针
{
	pNode fast = plist;
	pNode slow = plist;

	while(fast && fast->next)
	{
		fast = fast->next->next;
		slow = slow->next;
	}
	return slow;
}

 

10.查找单链表的倒数第k个节点,要求只能遍历一次链表

思路:快慢指针,快指针先走k-1步,然后快慢指针同时一步一步的走,当快指针走到链表结尾时,慢指针刚好指向第k个节点。

具体代码如下:

 

//删除单链表倒数第k个节点,时间复杂度o(N)
void DelKNode(pList* pplist,int k)
{
	pNode fast = *pplist;
	pNode slow = *pplist;
	assert(pplist);
	if(*pplist == NULL)
	{
		return;
	}
	while(fast->next != NULL)
	{
		--k;
		if(k<=0)
		{
			slow = slow->next;
		}
		fast = fast->next;
	}
	if(k<=0)
	{
		pNode del = slow->next;
		slow->data = slow->next->data;
		slow->next = slow->next->next;
		free(del);
	}
}

吐舌头更精彩的请见下一篇博客!

 

 

 

 

 



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值