2.從尾到頭打印單鏈表
3.刪除一個無頭單鏈表的非尾節點
4.在無頭單鏈表的一個節點前插入一個節點
5.單鏈表實現約瑟夫環
6.逆置/反轉單鏈表
7.單鏈表排序(冒泡排序&快速排序)
8.合併兩個有序鏈表,合併後依然有序
9.查找單鏈表的中間節點,要求只能遍歷一次鏈表
10.查找單鏈表的倒數第k個節點,要求只能遍歷一次鏈表
1、比較順序表和鏈表的優缺點,說說它們分別在什麼場景下使用?
給順序表設定容量的時候,如果每次分配的太小則要不斷地申請內存來給它使用,如果太大了則會造成內存浪費。假如當一個順序表每次增容100個字節,現在順序表裏剛剛存了100個數據,如果要是再想增加一個數據,那麼就要再申請100個字節的內存,而現在只需要一個,則剩下的99個字節就會被浪費。
在順序表裏如果要是前插一個數,就要先把後面的數據全部向後移動一位,然後再插入,這樣做會大大增加時間複雜度。
但是順序表在查找起來則比鏈表方便許多!鏈表在大量增加數據時比較方便!
2.從尾到頭打印單鏈表
要將單鏈表從後向前打印輸出有很多種方法,這裏我們用常規的方法和遞歸來寫一下
遞歸
void Printinverse(ListNode *plist)//從尾到頭打印鏈表
{
ListNode *tmp = plist;
while(tmp->next != NULL)
{
Printinverse(tmp->next);
break;
}
printf("%d->", tmp->data);
}
常規
void test(ListNode *plist)
{
ListNode *tail = NULL;//創造一個尾節點,當遍歷到尾時,讓tail想起移位,直到收尾相等
while(plist != tail)
{
ListNode *tmp = plist;
while(tmp->next != tail)
{
tmp = tmp->next;
}
tail = tmp;
printf("%d->", tail->data);
}
}
3.刪除一個無頭單鏈表的非尾節點
要刪除一個
void EraseNonHead(ListNode *pos)//.刪除一個無頭單鏈表的非尾節點
{//1->2->3->4->null
assert(pos);
ListNode *next = pos->next;
if(next != NULL)
{
pos->next = next->next;
pos->data = next->data;
}
free(next);
next = NULL;
}
void InsertNonHead(ListNode *pos, Datatype x)//無頭鏈表插入
{//1->2->3->4->NULL
assert(pos);
ListNode *cur = pos->next;
ListNode *tmp = BuyNode(x);
pos->next = tmp;
tmp->next = cur;
Datatype data = pos->data;
pos->data = tmp->data;
tmp->data = data;
}
5.單鏈表實現約瑟夫環
先來看看什麼是約瑟夫環
void JosephRing(ListNode **pplist, int x, int y, int z)//總共x個人,從第y個開始數,每次數z個人
{
int i = 0;
assert(pplist);
ListNode *tmp = NULL;
for(i=1; i<=x; i++)
{
PushBack(pplist, i);
}
tmp = Find(*pplist, x);
tmp->next = *pplist;
while(--y)
{
*pplist = (*pplist)->next;
}
while(*pplist != (*pplist)->next)
{
int count = z;
while(--count)
*pplist = (*pplist)->next;
printf("%d ", (*pplist)->data);
EraseNonHead(*pplist);
}
printf("\n");
printf("%d\n",(*pplist)->data);
}
6.逆置/反轉單鏈表
逆置一個單鏈表和從尾到頭打印不一樣,打印不改變節點的位置,只是將數據反着打印一遍,而逆置就是要改變節點的位置
可以先創建一個空節點,然後從第一個開始每次在單鏈表上拿一個節點,前插給創建的節點,單鏈表的頭結點往後移,創建的新節點往前移。當單鏈表爲空的時候,也就逆置完了。
ListNode *reverseList(ListNode **pplist)
{//1、當鏈表爲空或者只有一個節點的時候,直接返回 2、多個節點
if((*pplist == NULL) || ((*pplist)->next == NULL))
{
return *pplist;
}
else
{
ListNode *newlist = NULL;
ListNode *cur = *pplist;
while(cur)
{
ListNode *tmp = cur;
cur = cur->next;
tmp->next = newlist;
newlist = tmp;
}
return newlist;
}
}
7.單鏈表排序(冒泡排序&快速排序)
定義一個頭結點和尾節點,冒泡停止條件爲首節點的下個節點不爲尾節點,每次比較頭結點和下一個幾點,當頭結點大於下一個節點時交換數據,然後頭結點向後移位,直到頭結點的下個節點爲尾節點時,第一次排序完成然後把尾節點向前移動一位。
在冒泡的時候要注意什麼時候停下了,每次交換的次數!
ListNode *BubbleList(ListNode *plist)
{/*定義一個頭結點和尾節點,冒泡停止條件爲首節點的下個節點不爲尾節點,每次比較頭結點和下一
個幾點,當頭結點大於下一個節點時交換數據,然後頭結點向後移位,直到頭結點的下個節點爲
尾節點時,第一次排序完成然後把尾節點向前移動一位。*/
if(plist == NULL || plist->next == NULL)
{
return plist;
}
ListNode *tail = NULL;
ListNode *head = plist;
while(head->next != tail)
{
ListNode *tmp = head;
while(tmp->next != tail)
{
ListNode *next = tmp->next;
if(tmp->data >= next->data)
{
Datatype k = tmp->data;
tmp->data = next->data;
next->data = k;
}
tmp = next;
}
tail = tmp;
}
return head;
}
8.合併兩個有序鏈表,合併後依然有序
要合併兩個有序的鏈表就先把兩個鏈表頭結點的較小者先拿出來,然後頭結點向後移,依次比較他們的頭結點,不斷地往新鏈表的後面插,直到有一個爲空的時候就把另一個鏈表連接到新鏈表後面
ListNode *Merge(ListNode *plist1, ListNode *plist2)//摘節點法,創建新鏈表
{//鏈表爲空,兩個鏈表中只有一個有數據, 都有數據
if(plist1 == NULL && plist2 == NULL)//當全爲空時返回任意一個
{
return plist1;
}
if(plist1 == NULL && plist2 != NULL)//一個爲空就返回另一個
{
return plist2;
}
if(plist1 != NULL && plist2 == NULL)
{
return plist1;
}
else
{
ListNode *newlist = NULL;
ListNode *cur = NULL;
if(plist1->data >= plist2->data)//先判斷兩個頭結點哪一個大,把小的那個頭結點給新鏈表的頭
{
cur = plist2;
plist2 = plist2->next;
}
else
{
cur = plist1;
plist1 = plist1->next;
}
newlist = cur;//保存新鏈表的頭節點
while(plist1 != NULL && plist2 != NULL)//當兩個鏈表都不爲空時合併
{
if(plist1->data <= plist2->data)//把小的節點往新鏈表的後面串,直到有一個爲空
{
cur->next = plist1;
plist1 = plist1->next;
}
else
{
cur->next = plist2;
plist2 = plist2->next;
}
cur = cur->next;
}
if(plist1 == NULL)//當其中一個爲空之時,另一個鏈表直接連到新鏈表的後面
cur->next = plist2;
if(plist2 == NULL)
cur->next = plist1;
return newlist;
}
}
9.查找單鏈表的中間節點,要求只能遍歷一次鏈表
如果有兩個人,一個人走路一次走一步,另一個一次走兩步,則走兩步的人走過的步數一定時走一步人步數的兩倍。那麼就利用這個原理定義兩個節點,一個快節點一次走兩步,慢節點一次走一步,當快節點走完後,慢節點就是所要求的中間節點,但是要考慮當鏈表的節點個數爲奇數和偶數的時候。
ListNode *SearchmidNode(ListNode *plist)
{
assert(plist);
ListNode *slow = plist;
ListNode *fast = plist;
while(fast->next)
{
if(fast->next->next == NULL)//如果爲偶數個,在快指針的下下步爲空的時候只讓慢的走一步就返回
{
slow = slow->next;
break;
}
slow = slow->next;
fast = (fast->next)->next;
}
return slow;
}
10.查找單鏈表的倒數第k個節點,要求只能遍歷一次鏈表
ListNode *LastKNode(ListNode *plist, Datatype k)
{
assert(plist);
ListNode *slow = plist;
ListNode *fast = plist;
while(--k)
fast = fast->next;
while(fast->next)
{
slow = slow->next;
fast = fast->next;
}
return slow;
}