就是最簡單的迴圈計數struct listnode //定義鍊錶
採用「頭插法」,順序遍歷原鍊錶,挨個將結點頭插到新鍊錶中。int calculate(listnode *phead)
return nlength;
}
(注意要先把這個結點給copy一下,去把副本進行頭插,不然的話原鍊錶關係就斷了)
這樣的頭插法可以完美反轉鍊錶順序。
注意最開始要考慮鍊錶為空or鍊錶只有乙個結點(反轉無用)。
時間複雜度為o(n)
最普遍的方法是,先統計單鏈表中結點的個數,然後再找到第(n-k)個結點。注意鍊錶為空,k為0,k為1,k大於鍊錶中節點個數時的情況。時間複雜度為o(n)。**略。//頭插法!!!
listnode * reverse(listnode * phead)
return reversehead;
}
這裡主要講一下另乙個思路,這種思路在其他題目中也會有應用。
主要思路就是使用兩個指標,先讓前面的指標走到正向第k個結點,這樣前後兩個指標的距離差是k-1,之後前後兩個指標一起向前走,前面的指標走到最後乙個結點時,後面指標所指結點就是倒數第k個結點。
要注意特殊情況(k==0 鍊錶為空 鍊錶還沒k長)
此題可應用於上一題類似的思想。也是設定兩個指標,只不過這裡是,兩個指標同時向前走,前面的指標每次走兩步(那麼前面的指標總是比他多走一倍),後面的指標每次走一步,前面的指標走到最後乙個結點時,後面的指標所指結點就是中間結點,即第(n/2+1)個結點。listnode * lastk(listnode * phead , int k)
if(k>1) //說明鍊錶長度pnext!=null)
//退出while,說明before到達最後乙個結點
//after一直和before相差k-1
return after;
}
注意鍊錶為空,鍊錶結點個數為1和2的情況——也就是在遍歷中有可能讓指標指向空的情況。
時間複雜度o(n)
當然,用棧or遞迴!listnode * lastk(listnode * phead)
return after;
}
這裡也是用到兩個指標。如果乙個鍊錶中有環,也就是說用乙個指標去遍歷,是永遠走不到頭的。因此,我們可以用兩個指標去遍歷,乙個指標一次走兩步,乙個指標一次走一步,如果有環,兩個指標肯定會在環中相遇。時間複雜度為o(n)。stacks;
void rprintlist(listnode* phead)
//全部放入棧中後,依次出棧列印
while(s.isempty()==false)
else
listnode *neww_return = neww; //記錄新鍊錶的頭結點,用於最後返回用
while(phead1!=null && phead2!=null)
else
}//還剩下的話,直接接上
if(phead1!=null)
neww->pnext=phead1;
if(phead2!=null)
neww->pnext=phead2;
return neww_return;
}
如果兩個鍊錶相交於某一節點,那麼在這個相交節點之後的所有節點都是兩個鍊錶所共有的。也就是說,如果兩個鍊錶相交,那麼最後乙個節點肯定是共有的(看圖理解)。先遍歷第乙個鍊錶,記住最後乙個節點,然後遍歷第二個鍊錶,到最後乙個節點時和第乙個鍊錶的最後乙個節點做比較,如果相同,則相交,否則不相交。時間複雜度為o(len1+len2),因為只需要1or2個額外指標儲存最後乙個節點位址,空間複雜度為o(1)。bool hascircle(listnode* phead) //是否有環
//fast指標遍歷結束了,說明鍊錶並不是無止盡的,說明沒有環
return false;
}
鍊錶相交一定是下面這種形狀的,不可能是x字交叉的那種,你想嘛,乙個鍊錶結點又不可能有兩個pnext指標
//再找到鍊錶2的尾結點
while(p2->pnext!=null) //因為尾結點的pnext==null
if(p1==p2) //如果尾結點相同,說明相交
return true;
return false;
}剛開始我想得太簡單了,覺得就是兩個鍊錶一起同時走,每走一步判斷是否相同。
但是忘了考慮一點:兩個鍊錶並不是一樣長。
比較完善的思路是:先判斷是否相交(判斷最後乙個結點是否相同)——同時也是在計算兩個單鏈表的長度,然後再讓更長的的鍊錶先走多出來的長度,這樣兩個鍊錶當前節點到第乙個相交節點的距離就相等了,然後一起向後遍歷,直到兩個節點的位址相同。
對於有環的單鏈表,乙個fast乙個slow指標,等到二者相等,可以說明有環、遍歷無止盡,也說明讓二者相等的這個點在環上。這個時候,把這個點「解開」,可以得到如下圖所示的兩條相交的鍊錶listnode* firstintersection(listnode* phead1,listnode* phead2)
//再找到鍊錶2的尾結點
while(p2->pnext!=null) //因為尾結點的pnext==null
if(p1!=p2) //如果尾結點相同,說明相交
return null;
//尋找第乙個相交的結點
if(nlength1>=nlength2)//第乙個單鏈表更長 }
else //第二個單鏈表更長
} //這時候兩個鍊錶當前指標都離相交的第乙個結點距離相同
while(p1!=p2)
return p1;
}
。(對於單鏈表,我認為很重要的就是要注意鍊錶的方向!!!對程式設計很關鍵
)這個時候,問題就轉化為——求相交的第乙個結點!
//此時fast==slow並且是環上的乙個點,以此斷開變成兩條相交的單鏈表
listnode *new1 = head;
listnode *new2 = slow->next;
slow->next=null;
//肯定相交的(無需判斷最後乙個結點是否相同),直接去找交點
//先計算兩個單鏈表的長度,各自走到離交點的相等距離處
int len1=0,len2=0;
listnode *p1=new1;
listnode *p2=new2;
while(p1!=null)
while(p2!=null)
p1=new1; //注意再回到開頭
p2=new2;
if(len1next;
}else if(len1>len2)
//然後一起共同往前,直到相同即可
while(p1!=p2)
return p1;
}一般我們認為,單鏈表中的刪除操作的時間複雜度是o(n),是因為要首先找到該結點的頭結點,然後把p->next=p->next->next,然後free(ptobedeleted)。
但是,由於單鏈表的每個節點的結構是一樣的(標誌其實就是乙個值而已),所以其實可以把下乙個結點的值複製到這個結點,然後刪除下乙個結點。這樣的話,給出ptobedeleted指標,只需時間複雜度o(1)
但是,如果ptobedeleted是最後乙個結點,就沒辦法了,只能從頭遍歷找到倒數第二個結點,需o(n)。但平均來說,還是o(1)
我的天啊...我怎麼還是忘了考慮「鍊錶為空」和「鍊錶中只有乙個結點」的情況呢,以後關於鍊錶的題,最後一定要檢查下這兩個情況有沒有做考慮!void deletep(listnode*head,listnode* ptobedeleted)
if(ptobedeleted->pnext!=null) //不是最後乙個結點
else //是最後乙個結點,只能遍歷找前乙個
listnode* pp = head;
while(pp->pnext!=ptobedeleted)
pp=pp->pnext;
pp->pnext=null;
free(ptobedeleted);
} }
鍊錶演算法題
leetcode鏈結 利用棧先入先出 definition for singly linked list.struct listnode class solution p head while p p head 需要找到頭節點的位置 return p 雙指標,畫 決 leetcode鏈結 class...
鍊錶高頻演算法題
class solutionif l2 listnode dummy new listnode listnode res dummy res next null while l1 l2 else if l1 if l2 return dummy next class solution listnod...
鍊錶問題(演算法題)
1 從已排序的鍊錶中刪除重複的單元。如 輸入 1 1 2,輸出 1 2 如 輸入 1 1 2 2 3,輸出 1 2 3 思路 雙指標 快指標先往後移動,如果快指標的值不等於慢指標的值,就釋放掉中間的指標空間,並且將慢指標next指向快指標,把快指標賦值給快指標。node deleteduplicat...