链表操作面试题

#include <iostream>
using namespace std;

struct Node
{
	Node(int x)
	{
		value = x;
		next = NULL;
	}
	int value;
	Node *next;
};
Node* find(Node *pHead, int t);

//一、删除链表中某个节点
//思路:先找到要删除的节点位置
bool deletet(Node **pHead,int t)
{

	Node *p = find(*pHead,t);//先找到节点位置

	if (p == NULL)
	{
		return  false;
	}
	else
	{
		if (p == *pHead)//头结点
		{
			*pHead = p->next;
			delete p;
		}
		else
		{
			Node *pre = *pHead;
			while (pre->next != p)//获取p的前一个节点(循环结束后pre为p的前一个节点)
				pre = pre->next;

			pre->next = p->next;//跳过cur
			delete p;
		}
		return true;
	}
}

Node* find(Node *pHead, int val)
{
	while (pHead)//循环之后p为空节点
	{
		if (pHead->value == val)
		{
			return pHead;
		}

		pHead = pHead->next;

	}
	return NULL;
}

//二、在链表中某个元素面前插入一个元素,如果待查的元素不存在,则不插入
//思路:先根据待查元素找到要插入的位置,然后分头部插入和中间插入进行考虑

template<class T>
void  List<T>::insert(T oldt, T newt)
{
	Node<T> *p = find(oldt);
	if (p)
	{
		Node<T> *pnew = new Node<T>;
		pnew->value = newt;

		if (p == pHead)//头部插入
		{
			pnew->pNext = pHead;
			pHead = pnew;//更新头节点
			return;
		}
		Node<T> *pre, *cur;
		pre = pHead;
		while (pre->pNext != p)//循环结束后pre刚好在p的前面
			pre = pre->pNext;

		//pre pnew p三个节点都已知,那么连接无先后顺序
		pnew->pNext = p;
		pre->pNext = pnew;
	}
}

template <class T>
Node<T> * List<T>::find(T value)
{
	Node<T> *p = pHead;//获取头结点位置
	while (p)//循环之后p为空节点
	{
		if (p->value == value)
		{
			return p;
		}

		p = p->pNext;

	}
	return NULL;
}

//三、寻找单链表的中间结点

//方法1、遍历求长度length  然后再遍历输出
//方法2、双路齐下: p1走两步 p2走一步; p1走到终点时, p2正好到达中点

Node* findMiddle(Node *head)
{
	Node *p1 = head;
	Node *p2 = head;
	while (p1->next->next)
	{
		p1 = p1->next->next;
		p2 = p2->next;
	}
	return p2;
}

//四、寻找单链表中的倒数第k个元素

//方法1、先遍历一遍 计算长度, 再找出后k个
//方法2、双路齐下:
//       1.指针 p1 先从位置1开始后移k个位置,则 p1 移动到了位置k+1;
//       2.指针 p2 从位置1开始移动,同时 p1 从位置k+1继续移动,直到p1=NULL;
//         设链表长度为n,p1从位置k+1到p1=NULL,移动了n+1 - (k+1)=n-k;所以p2也移动了n - k,此时p2的位置是n-k+1,刚好是倒数第k个位置。

Node* findKth(Node* head, int k)//下标从1开始
{
	if (!head|| k<1)    
		return NULL;

	Node *p1, *p2;
	p1 = head;
	p2 = head;
	for (int i = 1; i <= k; i++)
	{
		if (p1)
			p1 = p1->next; //p1向后移k位
		else
			return NULL;//k如果大于节点数,那么p1为空,会引起程序崩溃,所以要加if判断,可参照剑指offer110页
	}

	while(p1)
	{
		p1 = p1->next;
		p2 = p2->next;
	}
	return p2;
}


//五、从某一个节点开始翻转单链表

//链表翻转:给出一个链表和一个数k,比如,链表为1→2→3→4→5→6
//若k = 2,则翻转后2→1→6→5→4→3;
//若k = 3,翻转后3→2→1→6→5→4;
//若k = 4,翻转后4→3→2→1→6→5;
//实质是也是逆置,只不过是两个链表逆置后再串联起来。实现如下:

bool rotateLinkedList(Node* &first, int k)//k在[1 、2.....len]取值
{
	//k只能为1~len之间
	if (k <= 0)
		return false;
	int len = 0;
	Node *node = first;
	while (node)
	{
		++len;
		node = node->next;
	}
	if (k > len)
		return false;

	//第一个逆置序列
	Node* pre = first;
	Node* cur = first->next;
	--k;
	Node* next = cur;//如果这里写成Node* next = 0;,当k=1时 ,由于没执行while,next不能指向第二个节点
	while (k /*&&cur*/)//可加可不加
	{
		next = cur->next;
		cur->next = pre;

		pre = cur;
		cur = next;
		--k;
	}
	Node* last = first;//保存第一个逆置序列的最后一个节点
	first->next = 0;
	first = pre;

	//第二个逆置序列
	if (next)//这里加个if语句,是为了当k=6时(最后一个位置),在完成第一个逆置序列后next =0,不执行括号里的语句
	{
		Node *link = next;
		pre = link;
		cur = link->next;
		next = NULL;
		while (cur)
		{
			next = cur->next;
			cur->next = pre;

			pre = cur;
			cur = next;
		}
		link->next = 0;
		last->next = pre;//第一个逆置序列的最后一个节点与第二个逆置序列的头节点prev连起来
	}

	return true /*first*/;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值