从尾打印链表
1 用递归的方法,如果当前节点不为空,继续调打印函数传过去的参数下一个节点。
If(PNode)
{
Print_list(PNode->PNext);
Printf(“%d->”,PNode->data);
}
2 删除一个非头节点的非尾节点(不能遍历链表)
用代替法,把当前节点的下一个节点的值赋值给当前节点,在delete掉当前节点的下一个节点。
3在无头单链表的一个非头节点前插入一个节点。
在当前节点后先把这个节点插入,再交换一个节点的值
4 单链表实现约瑟夫环
PNode Josephcirclr(PNode Phead, SIZE_t M)
它的主要思想是报数当为第M个节点是删除它,继续报数,返回最后一个节点。
{
pNode Cur=Phead;
PNode DelNode;
Size_t count;
While(Cur!=Cur->Pnext)
{
Count=M;
While(--M) // M-- 走M 次,--M走M-1次,因为第一个节点也算故走M-1次。
{
pCur=PCur->PNext;
}
DelNode=PCur->PNext;
PCur->PNext=DelNode->PNext;
PCur->data=DelNode->data;
Free(DelNode);
}
Return PCur;
}
5 单链表排序 (冒泡)
传一个参数为(PHead)
定义3个指针,PTail ,PCur,PNext.
PTail为尾随指针它为NULL,
当外部while(PHead!=PTail)控制冒泡次数,内部while(PNext!=PTail)控制排序次数,进去首先给PCur=Phead,PNext=Phead->PNext,然后进入内部while进行冒泡。
内部while,在走完一次冒泡后。PCur值为最后一个节点的值把它赋给PTail,PTail=PCur.
最终尾随指针走向head.
6找到中间节点
定义俩个指针一个为fast一个为low.fast走2步,low走一步。
While(fast&&fast->Next) fast=fast->Next->Next; low=low->Next. 出了while,low为中间节点
7找到 倒数第K个节点
定义俩个指针,fast先走第K步,low再走,当fast走到NULL,low为倒数第K个节点。
While(K--) { if(k==0)return ; fast=fast->Next;}while(fast){low=low->Next,fast=fast->Next;} return low;
K-- 对应fast , - -k对应fast->Pnext判断条件不同
8 逆制 单链表
方法1 . 3指针法
Pre PCur pnext ,用pre记录当前节点的前一个节点,当前节点Next指向pre,这样我们就完成了逆制,但是如果没有Next就会丢失链表,故这就是Next的意义了
2 递归
Node* rev (Node*PHead)
{
Node * PCur =PHead;
Node * Ppre =PHead;
static Node* ptemp =PHead;
static Node * ret =NULL;
if (NULL == PCur->_PNext)
{
ret = PCur;
}
if (PCur->_PNext)
{
Ppre = PCur;
PCur = PCur->_PNext;
rev(PCur);
PCur->_PNext = Ppre;
}
if (ptemp == Ppre)
{
Ppre->_PNext = NULL;
return ret;
} // 递归
}
3 头插法不创建新节点
Node * _rev_2(Node*PHead)
{
assert(PHead);
Node *pre =PHead;
Node * PCur = pre->_PNext;
Node* NewHead =NULL;
while (PCur)
{
pre->_PNext = NewHead; // ppre插入在新链表的头节点之前
NewHead = pre; // 头节点指向新的节点。
pre->_PNext = PCur;
PCur = PCur->_PNext;
}
pre->_PNext = NewHead; // 出while时 , PCur 指向 NULL ,ppre 指向最后一个节点故需处理最后一个节点在循环外
NewHead = pre;
return NewHead;
}
9 链表是否有交点,有的话返回交点。
如果有交点 那么最后一个节点肯定相同,因为相交意味着有一个相同的节点,那么这个节点之后的所有Next的节点都相同,故相交 最后一个节点都相同。
那么做法第一步遍历链表的同时 定义size_1 size_2 来一边遍历链表,一边记住链表大小。
那么遍历完 后得到俩链表的大小和最后一个节点。
第二步 看最后一个节点是否相同,如果相同的话那么一定相交。
相交后。 定义一个变量来记录他们的差值 gap, 用while(gap - -)来使长的链表一直向后走,
直到俩链表长度相同,得到新的一个长链表的节点,从这个节点开始俩链表长度相同。那么
我们开始从这个节点再次遍历 俩链表, 直到俩节点相同,找到交点。
10 链表是否带环,10(2)带环 环的长度,10(3)求入口点
10(1) 定义一个快指针 一次走2步 慢 指针一次走1步 ,那么如有环快指针必定入环,等慢指针走进环,快指针必定在慢指针走完环一圈内追上慢指针。故可判断有环。
注意while(fast && fast->Next) 因为fast=fast->next->next, 故得保住fast和fast->next不为空。
10(2) 环的长度很简单,由第一小问 返回的 是相遇的节点,定义个临时变量PNode= meetNode;那么while(PNode->Next!=meetNode)让PNode走一圈遍历边即可,应注意count应初始化为1, 如果初始化为0,相遇点没有算到里面
10(3) 第一种方法 定义俩个指针 一个为PH一个为PM,PM从相遇点走 ,PH从头节点走,俩个每次都走一步当俩相遇的时候为入口点.因为设环长度为r ,入口点到 头节点为L,入口点到相遇点为X . 由快慢指针相遇得到存在2(L+X)=n*r+(L+x)式子存在,得到L=n*r-x,L=(n-1)r+r-x 。那么举个列子当n=1时(n至少等于1,因为快指针至少在走一圈后追上慢指针),L=r-x.它表示从相遇点走r-x就定于L,L刚好为入口点到头节点距离,那么当一个从头开始走一个从相遇点开始走,当它们相遇时,PH=PM那个节点就是入口点。所以该公式L=(n-1)r+(r-x)代表,L这段距离等于n-1圈的长度加上r-x的长度,所以从PM开始每次走一步,从PH的开始每次走一步,只要相遇了,PM肯定是走了n-1圈加上r-x,而从相遇点走r-x后的该点必定是相遇点。
即具体代码就是,PM=meetNode,PH=Phead,while(PH!=PM)PM=PM->Next,PH=PH->Next。
11 链表是否相交(可能带环),相交求交点
俩个链表都不带环俩个链表都带环
俩个链表一个带一个不带 对于这种情况直接return NULL因为只要相交必定俩个都带或者俩个都不带
思路:
1先定义俩个fast和俩个low,遍历边。
2遍历完后可根据if ((fast == NULL || fast->_PNext == NULL) && (fast2 == NULL || fast2->_PNext == NULL))判断出俩个都不带环
对于不带环的,就定义俩个变量为PH,PH2,代表链表长度,分别变量链表到末尾,如何俩个末尾节点不相等那么俩链表肯定不相交returnNULL,如何相等的话,求gap
为俩长度的差,然后长的链表一直while(gap!=0) p=p->next,gap--; 这样向后走到俩链表长短都一样了,再同时遍历俩链表直到节点相同那么它就是入口点
3 if ((fast != NULL&&fast->_PNext!=NULL)&&(fast2 != NULL&&fast2->_PNext!=NULL))代表俩个都带环,那么先找到环的入口点Enter,Enter2,并记录头节点到入口点的
距离为PH1,PH2。先看入口点是否相等,相等代表有交点,不相等返回NULL。如果那距离一个等于0,就把该链表头结点返回去,代表该链表自成一环,那么又相交,交点肯定为该自成一环的头结点。否则俩个PH都大于0,那么计算出gap,长的走到gap为0时,俩链表相等了长度,再遍历相同节点,找到后返回即可。
4 进不去 2,3的代表一个有环,一个没环就返回NULL.
第3条分支,俩个都带环相交时的几种情景
12 复杂链表的复制,有random的链表如何复制。 即 该节点有3个字段,一个为值一个为Next指针,一个为random指针。
1 给每个节点后面都new一个 当前节点的副本,边复制边把他们连接起来。
2 给随机域赋值,则新节点的random就等于老节点随即域的random->Next.
3 把俩个链表拆分。