鏈表相關的算法題大匯總 — 數據結構之鏈表奇思妙想

http://blog.csdn.net/lanxuezaipiao/article/details/22100021


基本函數(具體代碼實現見后面)

1,構造節點

?//定義節點類型
struct Node
{
??? int value;
??? Node*next;
};

?

2,分配節點

//之所以要分配節點原因是需要在分配函數中進行初始化,并且也利于判斷是否分配成功。

Node* applyNode();

?

3,在頭部增加節點

//增加節點在頭部(無頭結點),返回值的原因是由于傳入并非指針的引用。
Node* addNodeH(Node* Head,Node* InsertNode);

?

4,在尾部增加節點

//增加節點在尾部(無頭結點),返回值的原因是由于傳入并非指針的引用。
Node* addNodeT(Node* Head,Node* InsertNode);

?

5,以升序方式增加節點
Node* addNodeSort(Node* Head,Node* InsertNode);

?

6,構造鏈表

//沒有額外的表頭結點。

//選擇參數choose分別對應以何種方式構造鏈表,1為頭部增加節點;2為尾部增加節點;3為升序增加節點。
Node* createList(int n,int choose);

?

7,打印鏈表
void printList(Node*Head);

?

8,釋放鏈表
void freeList(Node*& Head);

?

9,鏈表節點數
int numOfNodes(Node* Head);

?

10,定位函數

//傳入參數i表示第幾個節點(從1開始),返回該節點指針
Node* locateNodeI(Node*Head,int i);

?

11,查找函數

//查找值為value的鏈表
int SearchList(Node*Head,int value);

?

12,刪除節點

//刪除位置i的節點
bool deleteNodeI(Node*&Head,int i);

?

13,排序函數

//冒泡排序鏈表,具體的做法是“貍貓換太子”,即只交換節點中的值,對鏈表結構不做改動。
void sortList(Node*& Head);

?

高級函數(具體代碼實現見后面)

1.單鏈表反轉

思路1:O(n^2).

? ? ? ?我的做法是“貍貓換太子”,不進行改動鏈表結構,只首尾交換len/2次。但是在本函數中用到了定位函數,定位函數實際上是遍歷了一遍整個鏈表,所以綜合效率很低,達到O(n^2).

void reverseList(Node*Head)

思路2:O(n).

? ? ? ?就最一般的情況而言(沒有之前寫的那么多輔助函數,即條件單純為只有Head指向一個單鏈表)。那么可以實現O(n)效率。做法是用三個相鄰的指針進行遍歷,在遍歷的途中,更改指針方向。當然要注意鏈表數目分情況,和拆鏈的處理。

Node* reverseList2(Node*Head)

?

2.找出單鏈表的倒數第4個元素

思路1:O(2n)

? ? ? ? 先遍歷一遍鏈表記錄節點個數。然后定位該位置count-3,定位函數實際上也是遍歷一遍,所以總效率O(n)+O(n)

bool findLast4th1(Node*Head,int &ans)

思路2:O(n)

? ? ? ? 如果題目限制要求,僅允許遍歷一遍,則可以按如下方法進行。先定義兩個指針,第一個指針先走4步,然后從這時開始,第一個指針和第二個指針同時繼續走,即第一個指針和第二個指針相差4步。則第二個指針到頭時,第一個指針指向倒數第四個。注意要考慮鏈表長度。

bool findLast4th2(Node*Head,int &ans)

思路3:O(n)

? ? ? ? 做一個數組arr[4],讓我們遍歷單鏈表,把第1個、第5個、第9個……第4N+1個扔到arr[0],把第2個、第6個、第10個……第4N+2個扔到arr[1],把第3個、第7個、第11個……第4N+3個扔到arr[2],把第4個、第8個、第12個……第4N個扔到arr[3],這樣隨著單鏈表的遍歷結束,arr中存儲的就是單鏈表的最后4個元素,找到最后一個元素對應的arr[i],讓k=(i+1)%4,則arr[k]就是倒數第4個元素。如果不易理解,畫個圖就好了。注意增加的空間只需要4個,所以是常數級的。比如加到第5個節點時就會把arr[0]中的值沖掉。

bool findLast4th3(Node*Head,int &ans)

?

3.找出單鏈表的中間元素

思路1:O(2n)

? ? ? ? ?在函數的支持下,直接求整個鏈表的長度,然后定位中間元素。

bool getMiddleOne1(Node*Head,int&ans)

思路2:O(n)

? ? ? ? 如果仍要求只遍歷一遍。類似于上題,還是使用兩個指針first和second,只是first每次走一步,second每次走兩步:

bool getMiddleOne2(Node*Head,int&ans)

?

4.刪除無頭單鏈表的一個節點

思路:

? ? ? ?? 注意這里的要求是無頭鏈表,即未知Head指針。但是知道的是current指針指向該鏈表的某一位置。現在希望刪除該指針,而不影響整個鏈表。即雖然不知道Head指針,但是該鏈還是完整的。

? ? ? ? 首先需要明確一點,即current指針之前的鏈表段落是不可能知道的。這是由鏈表的單向性決定的。沒有任何技術可以做到這一點。

? ? ? ? 其次,刪除鏈表某節點,該節點不能是首節點,因為首節點一旦刪除,Head無法找到該鏈表了。

? ? ? ? 再次,刪除鏈表某節點,該節點不能是尾節點,因為尾節點一旦刪除,則尾節點的前一節點的指針域無法置0(因為單鏈無法回溯)。

? ? ? ? 所以題意解釋為:刪除無頭單鏈表的一個節點(既非首節點也非尾節點)。

? ? ? ? 解法是利用“貍貓換太子”。首先復制current指針的下一個節點的value到current節點中。然后刪除current的下一節點。

void deleteNoHeadList(Node*Head,Node*Current)

? ? ? ?? ? ? ??

4+.增加無頭單鏈表的一個節點,一個指針current指向單鏈表中的一個節點,在該節點之前增加一個節點insertNode。

思路:

? ? ? ? ?思路還是“貍貓換太子”,即在current之后增加一個節點insertNode,然后交換insertNode和current的值。

? ? ? ? ?由于在current之后增加節點這個操作在current指向首尾都可以實現。

? ? ? ? ?所以這道問題轉化為:增加無頭單鏈表的一個節點,current指針指向該鏈表某節點(可以為首尾),在其之前增加節點p。

void addNoHeadList(Node*Head,Node*Current,Node*insertNode)

?

5.兩個不交叉的有序鏈表的合并

思路:O(len1+len2)

? ? ? ? 合并的辦法如下,首先用Node*& 方式傳入兩個鏈表的頭指針Head1,Head2。用指針引用是因為最后要修改Head1和Head2均為NULL。否則可能被其他人誤引用了。然后定義一個合并后的鏈表的頭指針和尾指針Head和Tail。然后不斷比較Head1和Head2的首元素,加入到新的合并的鏈表中。注意一點這里的加入并不是先增加申請一個節點分配,然后刪除釋放原來的節點。而是直接將指針指向。也就是說在合并的過程中只是指針指向改變了,完全沒有申請新的內存和釋放節點空間。最后如果有一個Head1或Head2的已經空了,則直接將剩余鏈表連接到Head即可。當然要注意很多細節。

Node* mergeTwoList(Node*& Head1,Node*& Head2)

?

6.有個二級單鏈表,其中每個元素都含有一個指向一個單鏈表的指針。寫程序把這個二級鏈表稱一級單鏈表。

思路:

? ? ? ? 注意要重新定義二級單鏈表的結構,具體的算法是:把所有的下級單鏈表順次連接。即可。程序代碼略。

?

7.單鏈表交換任意兩個元素(不包括表頭)

思路:

? ? ? ? ? 利用“貍貓換太子”,不破壞鏈表結構,只交換二者Node* cur1和Node* cur2的指向的值。程序代碼略。

? ? ? ? ? 其中的任意兩個元素由外界給定該兩個節點的指針。

?

8.判斷單鏈表是否有環(6形狀)?如何找到環的“起始”點?如何知道環的長度?


思路:

? ? ? ? 注意分析題意,題意并非是說單鏈表完全成O形狀的環,而是說單鏈表成6形狀的環。

? ? ? ? 首先判斷是否有環:為此我們建立兩個指針,從Head一起向前跑,一個步長為1,一個步長為2,用

? while(直到步長2的跑到結尾)
{
檢查兩個指針是否相等,直到找到為止。
}

來進行判斷。

? ? ? ? ? ? 原因是,在這場跑步中,結束循環有兩種可能,其一是原來無環,所以2先跑到結尾,因為2比1快,二者不可能相等。其二是原來是有環的,因為這場賽跑永遠沒有z終點,但是在環中,由于2比1快,因而必定套圈,也即2追上了1,這在無環中是不可能出現的情況。

? ? ? ? ? ?而進行計算環的長度,只要找到交匯點,然后在圈中跑一次就可以了。

int getCircleLength(Node* cross)

bool judgeCircleExists(Node* Head)

? ? ? ??

9.判斷兩個單鏈表是否相交


? ? ? ? ? ? 注意這里是判斷是否相交。對于判斷問題來講,相對還是比較簡單的。注意單鏈表并非不能有重復元素。

思路1:O(len1*len2)

? ? ? ? ? ? 把第一個鏈表的指針值逐項存在hashtable中,遍歷第2個鏈表的每一項的指針值,如果能在第一個鏈表中找到,則必然相交。但是C++的STL模板中的hash不太會用。所以我使用了set集合,不過貌似set集合是使用遍歷的方式來查找元素是否在集合中的,所以效率是比較低的,至少在O(len1*len2)級別。

bool judgeIntersectList1(Node* Head1,Node* Head2)

思路2:O(len1+len2)

? ? ? ? ? 把一個鏈表A接在另一個鏈表B的末尾,如果有環,則必然相交。如何判斷有環呢?從A開始遍歷,如果能回到A的表頭,則肯定有環。

注意,在返回結果之前,要把剛才連接上的兩個鏈表斷開,恢復原狀。

bool judgeIntersectList2(Node* Head1,Node* Head2)

思路3:O(len1+len2)

? ? ? ? ?如果兩個鏈表的末尾元素相同(指針相同,即為同一個元素,而非值相等),則必相交。
bool judgeIntersectList3(Node* Head1,Node* Head2)

?

10.兩個單鏈表相交,計算相交點

思路1:

? ? ? ? ?分別遍歷兩個單鏈表,計算出它們的長度M和N,假設M比N大,則長度M的鏈表先前進M-N,然后兩個鏈表同時以步長1前進,前進的同時比較當前的元素,如果相同,則必是交點。
Node* getIntersectPoint(Node* Head1,Node* Head2)

思路2:

? ? ? ? ?將指針p1,p2定位到兩個鏈表的尾部,然后同時將兩個指針前移(不可以,因為是單向鏈表)

?

11.用鏈表模擬大整數加法運算

思路:

??????? 對于高精度大數計算,沒有數組那么高效,具體數組的做法參見OJ高精度,鏈表的好處是可以定義節點,其中包含指數次數和值兩部分,比如20001可以表示為(2,4)->(1,0)->NULL其中2表示值,4表示10的4次方。這樣的話如果數屬于稀疏型的則以較少的空間保存了值。具體程序略。

?

12.單鏈表排序

思路:

???????? 參見基本函數13://冒泡排序鏈表,具體的做法是“貍貓換太子”,即只交換節點中的值,對鏈表結構不做改動。

void sortList(Node*& Head);


?

13.刪除單鏈表中重復的元素

思路:

?????????用Hashtable輔助,遍歷一遍單鏈表就能搞定。同高級函數9的原因,我不太會使用C++STL中的hash。而如果使用set集合來存儲鏈表中的所有的值,實際上效率和每次重新遍歷單鏈表是一樣的。“用了c++標準庫中的set來保存訪問過的元素,所以很方便的就可以判斷當前節點是否在set集合中,直接使用set提供的find函數就可以了。而且使用set的查找在時間復雜度上比較低。”我不太清楚STL中set集合的實現方式,如果是基于類似hash結構的話,那自然效率O(1),而如果是數組的話,實際在遍歷一遍,所以效率O(n)。不過貌似后者的可能性大一些。

void DeleteDuplexElements(Node*Head);

?


基本函數代碼:

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2,分配節點

//分配節點
//將分配內存和初始化該節點放在一個函數中
Node* applyNode()
{
?Node* newNode;
?if((newNode=(Node*)malloc(sizeof(Node)))==NULL)
?{
??cout<<"分配內存失敗!"<<endl;
??::exit(0);
?}
?//建立該節點信息:
?cout<<"請輸入本節點值:"<<endl;
?cin>>newNode->value;
?newNode->next=NULL;
?return newNode;
}

3,在頭部增加節點

//在表頭增加節點
//在頭指針所指向的鏈表中增加一個節點,插入頭部
//這里必須要返回Node*來進行更新,因為傳入的Head是Node*類型,而非Node*&
Node* addNodeH(Node* Head,Node* InsertNode)
{
?if(Head==NULL)
?{
??Head=InsertNode;
?}
?else
?{
??InsertNode->next=Head;
??Head=InsertNode;
?}
?return Head;
}

4,在尾部增加節點

//在表尾增加節點
//在頭指針所指向的鏈表中增加一個節點,插入尾部
//這里必須要返回Node*來進行更新,因為傳入的Head是Node*類型,而非Node*&
Node* addNodeT(Node* Head,Node* InsertNode)
{
?if(Head==NULL)
?{
??Head=InsertNode;
?}
?else
?{
??Node* p=Head;
??while(p->next!=NULL)
??{
???p=p->next;
??}
??p->next=InsertNode;
?}
?return Head;
}

5,以升序方式增加節點

//以升序增加節點
//這里必須要返回Node*來進行更新,因為傳入的Head是Node*類型,而非Node*&
Node* addNodeSort(Node* Head,Node* InsertNode)
{
?if(Head==NULL)
?{
??Head=InsertNode;
?}
?else
?{
??Node* p=Head;
??//注意,這里把(p->value)<(InsertNode->value)放在p->next!=NULL前面是有原因的,這是避免為了考慮在Head->[4]加入[1]的情況
??while((p->value)<(InsertNode->value)&&p->next!=NULL)
??{
???p=p->next;
??}
??if((p->value)>=(InsertNode->value))//因為((p->value)>=(InsertNode->value))而退出!表示在p前增加節點(貍貓換太子)
??{
???//先在p后增加節點
???InsertNode->next=p->next;
???p->next=InsertNode;
???//再交換p和InsertNode的值
???swap(p->value,InsertNode->value);
??}
??else//因為(p->next==NULL)而退出!表示在尾增加節點
??{
???p->next=InsertNode;
??}

?}
?return Head;
}

6,構造鏈表

//建立n個節點的鏈表 choose=1,在表頭加入,choose=2在表尾加入,choose=3按value值升序加入
Node* createList(int n,int choose)
{
?Node *Head=NULL,*p=NULL;
?for(int i=0;i<n;i++)
?{
??p=applyNode();
??if(choose==1)
??{
???Head=addNodeH(Head,p);
??}
??else if(choose==2)
??{
???Head=addNodeT(Head,p);
??}
??else if(choose==3)
??{
???Head=addNodeSort(Head,p);
??}
?}
?return Head;
}

7,打印鏈表
//遍歷鏈表并輸出
void printList(Node*Head)
{
?Node*p=Head;
?while(p!=NULL)
?{
??cout<<p->value<<"->";
??p=p->next;
?}
?cout<<"NULL"<<endl;
}

8,釋放鏈表

//釋放鏈表
void freeList(Node*& Head)
{
?Node* tmp=Head;
?while(tmp!=NULL)
?{
??Head=Head->next;
??free(tmp);
??tmp=Head;
?}
?Head=NULL;?
}

9,鏈表節點數
//數節點個數
int numOfNodes(Node* Head)
{
?int count=0;
?while(Head!=NULL)
?{
??count++;
??Head=Head->next;
?}
?return count;
}

10,定位函數
//定位第i個節點,i從1開始
Node* locateNodeI(Node*Head,int i)
{
?//cout<<"定位"<<i<<"位置"<<endl;
?Node* pos=NULL;
?int count=numOfNodes(Head);
?if(i<=0||i>count)
?{
??cout<<"定位越界!"<<endl;
?}
?else?
?{
??pos=Head;
??for(int j=1;j<i;j++)
??{
???pos=pos->next;
??}
?}

?return pos;
}

11,查找函數
//查找值value并返回第一個出現該值的位置,如果需要引用其指針,可以再locate該位置
int SearchList(Node*Head,int value)
{
?Node* p=Head;
?int pos=0;
?bool find=false;
?while(p!=NULL)
?{
??pos++;
??if(p->value==value)
??{
???find=true;
???break;
??}
??p=p->next;
?}
?if(find)
??return pos;
?else?
??return -1;

}

12,刪除節點
//刪除某位置i的節點
bool deleteNodeI(Node*&Head,int i)
{
?Node* p=locateNodeI(Head,i);
?if(p==NULL)
?{
??return false;
?}
?else
?{
??if(p==Head)//說明p是頭節點。
??{
???Head=p->next;
???free(p);
??}
??else
??{
???Node* prep=locateNodeI(Head,i-1);//定位前一個,必定存在?
???prep->next=p->next;
???free(p);
??}
??return true;
?}
}

13,排序函數

//鏈表排序
//排序的方法是不破壞結構,有“貍貓換太子”的意思,只進行value的交換,不破壞鏈表結構
void sortList(Node*& Head)
{
?int count=numOfNodes(Head);
?if(count==0||count==1)
?{
??return ;
?}

?//冒泡排序
?bool exchange;
?for(int i=2;i<=count;i++)
?{???
??exchange=false;
??for(int j=count;j>=i;j--)
??{
???Node* p1=locateNodeI(Head,j);
???Node* p2=locateNodeI(Head,j-1);
???if(p1->value<p2->value)
???{
????exchange=true;
????swap(p1->value,p2->value);
???}
??}
??if(!exchange)
???break;
?}
}


高級函數代碼:

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

1.單鏈表反轉1

//單鏈表反轉(O(n^2))
void reverseList(Node*Head)
{
?int count=numOfNodes(Head);
?//“貍貓換太子”,首尾交換
?for(int i=1;i<=count/2;i++)
?{
??Node* p1=locateNodeI(Head,i);
??Node* p2=locateNodeI(Head,count+1-i);
??swap(p1->value,p2->value);
?}
}

1.單鏈表反轉2
//單鏈表反轉(O(n))
Node* reverseList2(Node*Head)
{
?if(Head==NULL||Head->next==NULL)//空鏈和單節點
?{
??return Head;
?}
?Node* p1=Head;
?Node* p2=Head->next;
?Node* p3=Head->next->next;
?if(p3==NULL)//只有兩個節點
?{
??p1->next=NULL;
??p2->next=p1;
??Head=p2;
??return Head;
?}
?else//至少三個節點
?{
??p1->next=NULL;
??while(p3!=NULL)
??{
???p2->next=p1;
???p1=p2;
???p2=p3;
???p3=p3->next;
??}
??p2->next=p1;
??Head=p2;
??return Head;
?}
}

2.找出單鏈表的倒數第4個元素1

//查找倒數第四個元素,傳入ans中 O(2N)
bool findLast4th1(Node*Head,int &ans)
{
?//先確定節點個數:
?int count=numOfNodes(Head);
?//定位count-4
?Node* p=locateNodeI(Head,count-3);
?if(p!=NULL)
?{
??ans=p->value;
??return true;
?}
?else?
?{
??return false;
?}
}

2.找出單鏈表的倒數第4個元素2

//查找倒數第四個元素,傳入ans中 O(N),只遍歷一遍
bool findLast4th2(Node*Head,int &ans)
{
?Node* p1=Head;
?Node* p2=Head;
?//p1先走4步。
?for(int i=0;i<4;i++)
?{
??if(p1!=NULL)
??{
???p1=p1->next;
??}
??else
??{
???return false;//肯定鏈表長度不夠
??}
?}
?//同步移動
?while(p1!=NULL)
?{
??p1=p1->next;
??p2=p2->next;
?}
?ans=p2->value;
?return true;

}

2.找出單鏈表的倒數第4個元素3

//查找倒數第四個元素,傳入ans中 O(N)
bool findLast4th3(Node*Head,int &ans)
{
?int arr[4];
?Node* p=Head;
?int i=0;
?int count=0;
?while(p!=NULL)
?{
??arr[i]=p->value;
??p=p->next;
??i=(i+1)%4;
??count++;
?}
?if(count<4)
?{
??return false;
?}
?else
?{
??ans=arr[i];
??return true;
?}
}

3.找出單鏈表的中間元素1

//獲取中間元素O(2n)
bool getMiddleOne1(Node*Head,int&ans)
{
?int count=numOfNodes(Head);
?if(count==0)
?{
??return false;
?}
?else
?{
??Node* p=locateNodeI(Head,(count+1)/2);
??ans=p->value;
??return true;
?}

}

3.找出單鏈表的中間元素2

//獲取中間元素O(n)
//類似于上題,還是使用兩個指針first和second,只是first每次走一步,second每次走兩步:
bool getMiddleOne2(Node*Head,int&ans)
{

?if(Head==NULL)//空鏈表
?{
??return false;
?}
?else
?{
??Node*first=Head;
??Node*second=Head->next;
??while(second!=NULL&&second->next!=NULL)
??{
???first=first->next;
???second=second->next;
???second=second->next;
??}
??ans=first->value;
??return true;
?}
}

4.刪除無頭單鏈表的一個節點

//刪除無頭單鏈表的非首尾節點"貍貓換太子";
void deleteNoHeadList(Node*Head,Node*Current)
{
?Node* p=Current->next;
?//一定是非首尾節點,否則會出錯
?Current->value=Current->next->value;
?Current->next=Current->next->next;
?free(p);
}

4+.增加無頭單鏈表的一個節點,一個指針current指向單鏈表中的一個節點,在該節點之前增加一個節點insertNode。
//增加無頭單鏈表的一個節點,current指針指向該鏈表某節點(可以為首尾),在其之前增加節點insertNode。
void addNoHeadList(Node*Head,Node*Current,Node*insertNode)
{
?insertNode->next=Current->next;
?Current->next=insertNode;
?swap(Current->value,insertNode->value);
}

5.兩個不交叉的有序鏈表的合并
//合并兩個有序的鏈表
Node* mergeTwoList(Node*& Head1,Node*& Head2)
{
?Node* Head=NULL;//合并后的鏈表
?Node* Tail=NULL;//合并后鏈表的尾指針

?//p1,p2遍歷兩個鏈表
?Node* p1=Head1;
?Node* p2=Head2;
?while(!(p1==NULL||p2==NULL))
?{
??if(p1->value<=p2->value)
??{
???if(Head==NULL)//第一個節點
???{
????Head=p1;
????Tail=Head;
???}
???else
???{
????Tail->next=p1;
????Tail=Tail->next;
???}
???p1=p1->next;
??}
??else
??{
???if(Head==NULL)//第一個節點
???{
????Head=p2;
????Tail=Head;
???}
???else
???{
????Tail->next=p2;
????Tail=Tail->next;
???}
???p2=p2->next;
??}
?}
?if(p1!=NULL)
?{
??if(Head!=NULL)
??{
???Tail->next=p1;
??}
??else
??{
???Head=p1;
??}
?}
?else if(p2!=NULL)
?{
??if(Head!=NULL)
??{
???Tail->next=p2;
??}
??else
??{
???Head=p2;
??}

?}
?Head1=NULL;
?Head2=NULL;
?return Head;
}

8.判斷單鏈表是否有環(6形狀)?如何找到環的“起始”點?如何知道環的長度?1
//計算單鏈表成環,環的長度,輸入的參數為成環的交匯點。
int getCircleLength(Node* cross)
{
?int len=1;
?Node* p=cross;
?while(p->next!=cross)//千萬不能寫作p->next!=p
?{
??len++;
??p=p->next;
?}
?return len;
}

8.判斷單鏈表是否有環(6形狀)?如何找到環的“起始”點?如何知道環的長度?2

//判斷單鏈表是否有環,并且返回環的長度
bool judgeCircleExists(Node* Head,int &len)
{
?
?if(Head==NULL)//空鏈
?{
??return false;
?}
?else if(Head->next==Head)//1個節點且成環
?{
??return true;
?}
?else if(Head->next==NULL)//1個節點不成環
?{
??return false;
?}

?//至少兩個節點情形
?//初始化跑步機
?Node* p1=Head;//跑步者1號,跑到第1個節點
?Node* p2=Head->next;//跑步者2號,跑到第2個節點
?while(p2!=NULL&&p2->next!=NULL)//利用了&&短路
?{
??p1=p1->next;
??p2=p2->next->next;
??if(p1==p2)
??{
???//此時p1(p2)即為交匯點
???len=getCircleLength(p1);
???return true;
??}
?}
?return false;

}

9.判斷兩個單鏈表是否相交1
//判斷兩個單鏈表是否相交(Y型)
bool? judgeIntersectList1(Node* Head1,Node* Head2)
{
?set<Node*>s;

?Node* p1=Head1;
?Node* p2=Head2;
?while(p1!=NULL)
?{
??s.insert(p1);
??p1=p1->next;
?}
?while(p2!=NULL)
?{
??if(s.find(p2)!=s.end())
??{
???s.clear();
???return true;
??}
??p2=p2->next;
?}
?s.clear();
?return false;
}

9.判斷兩個單鏈表是否相交2

//判斷兩個單鏈表是否相交(Y型)
bool? judgeIntersectList2(Node* Head1,Node* Head2)
{
?if(Head1==NULL||Head2==NULL)
?{
??return false;
?}

?Node* p1=Head1;
?Node* p2=Head2;
?//先找到鏈表2的末尾,由p2指向
?while(p2->next!=NULL)
?{
??p2=p2->next;
?}
?//將鏈表1的表頭與鏈表2的表尾連接
?p2->next=p1;
?//遍歷鏈表1,如果回到了鏈表1表頭,則相交
?while(p1!=NULL)
?{
??if(p1->next==Head1)
??{
???//記得恢復原狀:
???p2->next=NULL;
???return true;
??}
??p1=p1->next;
?}
?//記得恢復原狀:
???? p2->next=NULL;
?return false;
}

9.判斷兩個單鏈表是否相交3

//判斷兩個單鏈表是否相交(Y型)
bool? judgeIntersectList3(Node* Head1,Node* Head2)
{
?if(Head1==NULL||Head2==NULL)
?{
??return false;
?}

?Node* p1=Head1;
?Node* p2=Head2;
?//p1與p2記錄兩鏈表的尾指針
?while(p1->next!=NULL)
?{
??p1=p1->next;
?}
?while(p2->next!=NULL)
?{
??p2=p2->next;
?}
?if(p1==p2)
?{
??return true;
?}
?return false;
}

10.兩個單鏈表相交,計算相交點
//兩鏈表相交,計算相交點:
Node* getIntersectPoint(Node* Head1,Node* Head2)
{
?int len1=numOfNodes(Head1);
?int len2=numOfNodes(Head2);
?int initMove=abs(len1-len2);
?Node* p1=Head1;
?Node* p2=Head2;

?if(len1>len2)
?{
??for(int i=0;i<initMove;i++)
??{
???p1=p1->next;
??}
?}
?else
?{
??for(int i=0;i<initMove;i++)
??{
???p2=p2->next;
??}
?}
?while(p1!=NULL&&p2!=NULL)
?{
??if(p1==p2)
??{
???return p1;
??}
??p1=p1->next;
??p2=p2->next;

?}
?return NULL;
}

12.單鏈表排序

//鏈表排序
//排序的方法是不破壞結構,有“貍貓換太子”的意思,只進行value的交換,不破壞鏈表結構
void sortList(Node*& Head)
{
?int count=numOfNodes(Head);
?if(count==0||count==1)
?{
??return ;
?}

?//冒泡排序
?bool exchange;
?for(int i=2;i<=count;i++)
?{???
??exchange=false;
??for(int j=count;j>=i;j--)
??{
???Node* p1=locateNodeI(Head,j);
???Node* p2=locateNodeI(Head,j-1);
???if(p1->value<p2->value)
???{
????exchange=true;
????swap(p1->value,p2->value);
???}
??}
??if(!exchange)
???break;
?}
}

13.刪除單鏈表中重復的元素

//刪除單鏈表中的重復元素:使用set集合來實現:
void DeleteDuplexElements(Node*Head)
{
?if(Head==NULL||Head->next==NULL)//鏈表為空或者只有一個元素
?{
??return ;
?}

?//以下至少兩個元素
?set<int>s;
?Node* p1=Head;
?Node* p2=Head->next;
?s.clear();
?s.insert(p1->value);
?while(p2!=NULL)//要刪除的不可能是鏈表頭,因為如果是鏈表頭,則集合還為空。
?{
??if(s.find(p2->value)==s.end())//沒有
??{
?? s.insert(p2->value);
?? p2=p2->next;
?? p1=p1->next;
??}
??else//已經有,則要刪除該節點
??{
???//不可能是鏈表頭
???//如果是鏈表尾
???if(p2->next==NULL)
???{
????p1->next=NULL;
????free(p2);
????p2=NULL;
???}
???else
???{
????p1->next=p2->next;
????free(p2);
????p2=p1->next;
???}
??}
?}
}




本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/384093.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/384093.shtml
英文地址,請注明出處:http://en.pswp.cn/news/384093.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

CodeForces - 372CWatching Fireworks is Fun+DP+單調隊列優化

【題目描述】 CodeForces - 372CWatching Fireworks is Fun 題目的大概意思就是在一個編號為1…n的街道上現在按照時間順序放煙花&#xff0c;每個煙花獲得的幸福感為b?abs(a?x)b-abs(a-x)b?abs(a?x)&#xff0c;x為觀看煙花的位置&#xff0c;為了提升我們的幸福感&#x…

雙向鏈表的基本操作

1.雙向鏈表的數據結構 typedef char DLinkType;typedef struct DLinkNode { DLinkType data; struct DLinkNode* next; struct DLinkNode* prev; }DLinkNode; 雙向帶頭結點的鏈表有三個成員&#xff0c; 一個是數據&#xff0c; 一個是指針 next 指向當前結點的下一個結點&…

匿名管道

1.進程通信的目的 (1) 數據傳輸: 一個進程需要將它的數據傳輸給另一個進程 ????(2) 資源共享: 多個進程之間共享同樣的資源 ????(3) 通知事件: 一個進程需要向另一個或一組進程發送消息, 通知它們發生了什么事情 2.管道 管道是一種進程之間通信的一種方式, 我們把從…

Currency Exchange——最短路Bellman-Ford算法

【題目描述】 Several currency exchange points are working in our city. Let us suppose that each point specializes in two particular currencies and performs exchange operations only with these currencies. There can be several points specializing in the sam…

C++實現String類

http://blog.csdn.net/randyjiawenjie/article/details/6709539 C實現String類&#xff0c;還沒有完成&#xff0c;待繼續。 有以下注意的點&#xff1a; &#xff08;1&#xff09;賦值操作符返回的是一個MyString&&#xff0c;而重載的返回的是一個MyString。其中的原因…

POJ 3370 Halloween treats——鴿巢原理+思維

【題目描述】 POJ 3370 Halloween treats Description Every year there is the same problem at Halloween: Each neighbour is only willing to give a certain total number of sweets on that day, no matter how many children call on him, so it may happen that a chi…

將信號量代碼生成靜態庫以及動態庫

1.信號量相關代碼生成靜態庫 2.信號量相關代碼生成動態庫

Wormholes——Bellman-Ford判斷負環

【題目描述】 While exploring his many farms, Farmer John has discovered a number of amazing wormholes. A wormhole is very peculiar because it is a one-way path that delivers you to its destination at a time that is BEFORE you entered the wormhole! Each of…

C++11 標準新特性:Defaulted 和 Deleted 函數

https://www.ibm.com/developerworks/cn/aix/library/1212_lufang_c11new/index.html Defaulted 函數 背景問題 C 的類有四類特殊成員函數&#xff0c;它們分別是&#xff1a;默認構造函數、析構函數、拷貝構造函數以及拷貝賦值運算符。這些類的特殊成員函數負責創建、初始化、…

順序表實現棧相關操作

1.棧的相關概念 棧是一種特殊的線性表, 其中只允許在固定的一端進行插入和刪除元素.進行數據插入和刪除的一端叫做棧頂, 另一端成為棧底. 不含任何元素的棧稱為空棧, 棧又稱為先進先出的線性表. 2. 順序棧的結構 3. 順序棧的具體操作 (1). 數據結構 typedef char SeqStackTyp…

MPI Maelstrom——Dijkstra

【題目描述】 BIT has recently taken delivery of their new supercomputer, a 32 processor Apollo Odyssey distributed shared memory machine with a hierarchical communication subsystem. Valentine McKee’s research advisor, Jack Swigert, has asked her to bench…

雙向帶環帶頭結點的鏈表實現棧

1. 數據結構 利用帶頭結點帶環的結點實現棧的相關操作.因此, 每一個結點包括了一個前驅, 一個后繼, 還有一個數據成員 typedef char DLinkStackType;typedef struct DLinkStack {DLinkStackType data;struct DLinkStack* next;struct DLinkStack* prev; }DLinkStack;2. 初始化…

Cow Contest——Floyed+連通性判斷

【題目描述】 N (1 ≤ N ≤ 100) cows, conveniently numbered 1…N, are participating in a programming contest. As we all know, some cows code better than others. Each cow has a certain constant skill rating that is unique among the competitors. The contest …

C++11 標準新特性:委派構造函數

https://www.ibm.com/developerworks/cn/rational/1508_chenjing_c11/index.html陳 晶2015 年 8 月 11 日發布WeiboGoogle用電子郵件發送本頁面 1本文首先介紹了在委派構造函數提出之前類成員構造所面臨的問題&#xff0c;再結合實例介紹了委派構造函數的用法&#xff0c;并說明…

順序表實現隊列

一. 隊列相關概念 隊列是只允許在一段進行插入元素, 在另一端進行刪除元素的線性表,即只允許對隊列進行尾插,頭刪的操作.隊列具有先進先出, 后進后出的特性. ???????? 1.初始化 void SeqQueInit(SeqQue* q) {if(q NULL){return;//非法輸入}q -> head 0;q -> …

Arbitrage——判斷正環Bellman-Ford/SPFA

【題目描述】 Arbitrage is the use of discrepancies in currency exchange rates to transform one unit of a currency into more than one unit of the same currency. For example, suppose that 1 US Dollar buys 0.5 British pound, 1 British pound buys 10.0 French …

鏈表實現隊列

上篇博客是用順序表實現隊列, 現在用雙向帶頭結點帶環鏈表實現對隊列的出隊列, 入隊列, 取隊首元素, 以及銷毀隊列的相關操作 1.初始化鏈表 void DLinkQueInit(DLinkQue** q) {if(q NULL){return;//非法輸入}if(*q NULL){return;//非法輸入帶頭結點的鏈表至少有一個傀儡結點…

HDU - 1796——容斥原理+二進制枚舉

【題目描述】 Now you get a number N, and a M-integers set, you should find out how many integers which are small than N, that they can divided exactly by any integers in the set. For example, N12, and M-integer set is {2,3}, so there is another set {2,3,4,…

數據結構學習(二)——單鏈表的操作之頭插法和尾插法創建鏈表

http://blog.csdn.net/abclixu123/article/details/8210109 鏈表也是線性表的一種&#xff0c;與順序表不同的是&#xff0c;它在內存中不是連續存放的。在C語言中&#xff0c;鏈表是通過指針相關實現的。而單鏈表是鏈表的其中一種&#xff0c;關于單鏈表就是其節點中有數據域和…

信號的基本概念以及信號的產生

一. 信號產生的場景 1. 用戶輸入命令, 在shell 啟動一個前臺進程 ???? 2. 當用戶按一下 Ctrl C 的時候,從鍵盤產生一個硬件中斷 ???? 3. 此時CPU 正在執行這個進程的帶代碼, 則該進程的執行代碼暫停執行, CPU 從用戶態切換到內核態處理該硬件中斷. ???? 4. 中斷…