#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*/;
}
链表操作面试题
最新推荐文章于 2022-04-06 17:17:52 发布