連結串列的各種基本操作
阿新 • • 發佈:2019-02-12
1. 連結串列定義。
#ifndef _LISTNODE_
#define _LISTNODE_
struct ListNode
{
int m_value;
ListNode * m_pNext;
};
#endif
2. 初始化連結串列。
void InitList(ListNode * L)
{
L = nullptr;
cout << "InitList Success! " << endl;
}
3. 建立連結串列。共三種方法。
// ------建立線性表 1: 頭結點插入法,頭結點不放資料------ ListNode * CreateListFromHead() { ListNode * pHead = new ListNode; pHead->m_pNext = nullptr; if (pHead == nullptr) { cout << "分配記憶體失敗!" << endl; return nullptr; } int input; while (cin>>input && input != -1) { ListNode *pTmp = new ListNode; pTmp->m_value = input; pTmp->m_pNext = pHead->m_pNext; //將節點插入到表頭,這是頭插法 pHead->m_pNext = pTmp; pTmp = nullptr; } //pTmp = nullptr; return pHead; }
// ------建立線性表 2: 尾插法,頭結點不放資料------ ListNode * CreateListFromTail2() { ListNode * pHead = new ListNode; if (pHead == nullptr) { cout << "分配記憶體失敗!" << endl; return nullptr; } pHead->m_pNext = nullptr; ListNode *pTail = new ListNode; pTail = pHead; int input; while (cin>>input && input != -1) { ListNode *pTmp = new ListNode; pTmp->m_value = input; pTail->m_pNext = pTmp; //尾插法 pTail = pTmp; pTmp = nullptr; } pTail->m_pNext = nullptr; return pHead; }
// ------建立線性表 3: 尾插法,無頭結點------ ListNode * CreateListFromTail() { /*ListNode * pHead = new ListNode; if (pHead == nullptr) { cout << "分配記憶體失敗!" << endl; return nullptr; }*/ ListNode *pHead = nullptr; ListNode *pTail = pHead; int input; while (cin>>input && input != -1) { ListNode *pTmp = new ListNode; pTmp->m_value = input; if (pHead == nullptr) pHead = pTmp; else pTail->m_pNext = pTmp; //尾插法 pTail = pTmp; pTmp = nullptr; } if (pTail != nullptr) pTail->m_pNext = nullptr; return pHead; }
4. 插入。共兩種方法。
// -------------------在pos位置的前方插入-----------------------------
void InsertListNodeFromFront(ListNode *&L, int pos, int value) //可能需要改變頭結點,因此L要取&
{
ListNode *tmp = new ListNode;
tmp->m_value = value;
if (L == nullptr || pos == 0)
{
tmp->m_pNext = L;
L = tmp;
return;
}
if ( pos >= ListLen(L) || pos < 0)
{
cout << "Error input pos."<< endl;
return;
}
ListNode *pInsert = L;
while (--pos)
{
pInsert = pInsert->m_pNext;
}
tmp->m_pNext = pInsert->m_pNext;
pInsert->m_pNext = tmp;
return;
}
// -----------------在pos後插入--------------------
void InsertListNodeFromBack(ListNode *&L, int pos, int value)
{
ListNode *tmp = new ListNode;
tmp->m_value = value;
if (L == nullptr || pos == 0)
{
tmp->m_pNext = L;
L = tmp;
return;
}
if ( pos >= ListLen(L) || pos < 0)
{
cout << "Error input pos."<< endl;
return;
}
ListNode *pInsert = L;
while (pos--)
{
pInsert = pInsert->m_pNext;
}
tmp->m_pNext = pInsert->m_pNext;
pInsert->m_pNext = tmp;
return;
}
5. 刪除。
void DeleteListNode(ListNode *&L, int value)
{
if (L == nullptr)
{
cout << "Error input L.";
return;
}
ListNode *pDelete = L;
if (L->m_value == value)
{
L = L->m_pNext;
delete pDelete;
return;
}
ListNode *pFront = nullptr;
while (pDelete != nullptr && pDelete->m_value != value)
{
pFront = pDelete;
pDelete = pDelete->m_pNext;
}
if (pDelete == nullptr)
{
cout << "Not found value in L.";
return;
}
if (pDelete->m_value == value)
{
pFront->m_pNext = pDelete->m_pNext;
delete pDelete;
}
return;
}
6. 翻轉。
ListNode * ReverseList(ListNode *L)
{
if(L == nullptr || L->m_pNext == nullptr)
return nullptr;
ListNode * pCurrent = nullptr;
while (L != nullptr)
{
ListNode * tmp = L->m_pNext;
L->m_pNext = pCurrent;
pCurrent = L;
L = tmp;
}
/*DisplayList(L);
DisplayList(pCurrent);*/
return pCurrent;
}
7. 列印。
void DisplayList(ListNode * L)
{
ListNode * list = L;
while (list != nullptr)
{
cout << list->m_value << " -> ";
list = list->m_pNext;
}
cout << "null" << endl;
}
8. 連結串列長度。
int ListLen(ListNode *L)
{
int len = 0;
while (L != nullptr)
{
L = L->m_pNext;
++len;
}
return len;
}
9. 找到連結串列倒數第k個節點。
ListNode *FindKthNode(ListNode *L, int k)
{
if (ListLen(L) < k)
return nullptr;
ListNode *pFront = nullptr, *pBack = nullptr;
pFront = pBack = L;
int ii = 0;
while (ii++ < k-1)
{
pFront = pFront->m_pNext;
}
while (pFront->m_pNext != nullptr)
{
pFront = pFront->m_pNext;
pBack = pBack->m_pNext;
}
return pBack;
}
10. 合併兩排序的連結串列。
ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{
if (pHead1 == nullptr)
return pHead2;
if (pHead2 == nullptr)
return pHead1;
ListNode *pNewHead = nullptr, *pNewTail = nullptr;
ListNode *pNode1 = pHead1, *pNode2 = pHead2;
while (pNode1 != nullptr && pNode2 != nullptr)
{
ListNode *pTmp = nullptr;
if (pNode1->val < pNode2->val)
{
pTmp = pNode1;
pNode1 = pNode1->next;
}
else
{
pTmp = pNode2;
pNode2 = pNode2->next;
}
if (pNewHead == nullptr)
{
pNewHead = pNewTail = pTmp;
}
else
{
pNewTail->next = pTmp;
pNewTail = pNewTail->next;
}
}
if ( pNode1 == nullptr ) //和歸併排序時的判斷條件不一樣。
{
pNewTail->next = pNode2;
}
if ( pNode2 == nullptr )
{
pNewTail->next = pNode1;
}
return pNewHead;
}
11. 刪除連結串列中重複的節點. 180420
ListNode* deleteDuplication(ListNode* pHead)
{
if(pHead == nullptr)
return nullptr;
if (pHead->next == nullptr)
return pHead;
if (pHead->val == pHead->next->val && pHead->next->next == nullptr)
return nullptr;
ListNode *pNewNode = new ListNode(-1);
pNewNode->next = pHead;
ListNode *pLastNode = pNewNode;
ListNode *pCurNode = pHead;
ListNode *pNextNode = pHead->next;
int flag = 0;
while (pNextNode != nullptr)
{
while (pNextNode && pCurNode->val == pNextNode->val)
{
pNextNode = pNextNode->next;
pCurNode->next = pNextNode;
flag = 1;
}
if ( flag )
{
pCurNode = pNextNode;
pLastNode->next = pCurNode;
flag = 0;
if (pNextNode)
pNextNode = pNextNode->next;
}
if (pNextNode && pCurNode->val != pNextNode->val)
{
pLastNode = pLastNode->next;
pCurNode = pCurNode->next;
pNextNode = pNextNode->next;
}
}
return pNewNode->next;
}
12. 找兩個連結串列第一個公共節點。 180424
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2)
{
if (pHead1 == nullptr || pHead2 == nullptr)
return nullptr;
ListNode *pNode1 = pHead1, *pNode2 = pHead2;
int cnt1 = 0, cnt2 = 0;
while (pNode1)
{
cnt1++;
pNode1 = pNode1->next;
}
while (pNode2)
{
cnt2++;
pNode2 = pNode2->next;
}
pNode1 = (cnt1>cnt2) ? pHead1 : pHead2;
pNode2 = (cnt1>cnt2) ? pHead2 : pHead1;
for (int ii=0; ii!=abs(cnt1-cnt2); ++ii)
pNode1 = pNode1->next;
ListNode * pRet = nullptr;
while (pNode1 && pNode2)
{
if (pNode1 == pNode2)
{
pRet = pNode1;
break;
}
else
{
pNode1 = pNode1->next;
pNode2 = pNode2->next;
}
}
return pRet;
}
13. 複雜連結串列的複製。180424
struct RandomListNode {
int label;
struct RandomListNode *next, *random;
RandomListNode(int x) :
label(x), next(NULL), random(NULL) {
}
};
// ---------------牛客網大神通過的版本---------------
RandomListNode* Clone(RandomListNode* pHead )
{
if(!pHead)
return NULL;
RandomListNode *currNode = pHead;
while(currNode)
{
RandomListNode *node = new RandomListNode(currNode->label);
node->next = currNode->next;
currNode->next = node;
currNode = node->next;
}
currNode = pHead;
while(currNode)
{
RandomListNode *node = currNode->next;
if (currNode->random)
node->random = currNode->random->next;
currNode = node->next;
}
//拆分
RandomListNode *pCloneHead = pHead->next;
RandomListNode *tmp;
currNode = pHead;
while(currNode->next)
{
tmp = currNode->next;
currNode->next =tmp->next;
currNode = tmp;
}
return pCloneHead;
}
// ------------ 自己的版本,未通過,錯誤尚未找出-------------
RandomListNode* Clone(RandomListNode* pHead)
{
if (pHead == nullptr)
return nullptr;
// ------------ 拷貝----------------
RandomListNode *pNode = pHead;
while (pNode)
{
RandomListNode *pTmp = new RandomListNode(*pNode);
pTmp->next = pNode->next;
pNode->next = pTmp;
if (pNode->random)
pTmp->random = pNode->random->next;
pNode = pTmp->next;
pTmp = nullptr;
}
// ------------- 拆分-----------------
pNode = pHead;
RandomListNode *pNewHead = pHead->next;
RandomListNode *pProcNode = pNewHead;
if (pNode) // 要讓pNode走在pProcNode的前面。
{
pNode->next = pProcNode->next;
pNode = pNode->next;
}
while (pProcNode && pNode)
{
pProcNode->next = pNode->next; // pNode後面不會是空,所以這樣賦值可以確保pProcNode後面不會是空
pProcNode = pProcNode->next;
pNode->next = pProcNode->next;
pNode = pNode->next;
}
return pNewHead;
}
14. 尋找連結串列中環的入口節點。180425
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
if(pHead == nullptr || pHead->next == nullptr)
return nullptr;
ListNode *pFast = pHead, *pLow = pHead;
// ----------- 獲取環的大小------------
int cnt = 0;
pFast = pFast->next;
pFast = (pFast==nullptr) ? pFast : pFast->next;
pLow = pLow->next;
++cnt;
while (pFast != pLow && pFast)
{
pFast = pFast->next;
pFast = (pFast==nullptr) ? pFast : pFast->next;
pLow = pLow->next;
++cnt;
}
if (pFast == nullptr)
return nullptr;
// --------獲取環的入口-----------
pFast = pLow = pHead;
ListNode *pRet = nullptr;
for (int ii=0; ii != cnt; ++ii)
pFast = pFast->next;
while (pFast != pLow)
{
pFast = pFast->next;
pLow = pLow->next;
}
pRet = pFast;
return pRet;
}
15. 主函式測試。
int main(int argc, char **argv)
{
ListNode * L = new ListNode;
InitList(L);
cout << "請輸入連結串列節點,以-1結束:" << endl;
L = CreateListFromTail();
DisplayList(L);
int pos = 1, value = 10;
cout << "在指定位置 " << pos << " 前方插入節點:" << value << endl;
InsertListNodeFromFront(L, pos, value);
DisplayList(L);
pos = 2; value = 20;
cout << "在指定位置 " << pos << " 後方插入節點:" << value << endl;
InsertListNodeFromBack(L, pos, value);
DisplayList(L);
cout << "刪除值為 " << value << " 的節點:" << endl;
DeleteListNode(L, value);
DisplayList(L);
cout << "翻轉連結串列:" << endl;
ListNode *R = ReverseList(L);
DisplayList(R);
getchar();getchar();
return 0;
}
測試結果: