1.比較順序表和鏈表的優缺點,說說它們分別在什麼場景下使用?
(1). 順序表支持隨機訪問,單鏈表不支持隨機訪問。
(2). 順序表插入/刪除數據效率很低,時間複雜度爲O(N)(除尾插尾刪),單鏈表插入/刪除效率更高,時間複雜度爲O(1)。
(3). 順序表的CPU高速緩存效率更高,單鏈表CPU高速緩存效率低。
2.從尾到頭打印單鏈表
void reverse(ListNode* plist)
{
if (NULL == plist)
{
printf("NULL");
return;
}
reverse(plist->next);
printf("<-%d", plist->data);
}
3.刪除一個無頭單鏈表的非尾節點
void EraseNonTail(ListNode* pos)
{
assert(pos);
assert(pos->next);
ListNode* next = pos->next;
pos->data = next->data;
pos->next = next->next;
free(next);
next = NULL;
}
4.在無頭單鏈表的一個節點前插入一個節點
void InsertNonTeal(ListNode *pos, DataType x)
{
assert(pos);
ListNode* newnode = BuyNode(x);
ListNode* next = pos->next;
pos->next = newnode;
newnode->next = next;
newnode->data = pos->data;
pos->data = x;
}
5.單鏈表實現約瑟夫環
約瑟夫環(約瑟夫問題)是一個數學的應用問題:已知n個人(以編號1,2,3…n分別表示)圍坐在一張圓桌周圍。從編號爲k的人開始報數,數到m的那個人出列;他的下一個人又從1開始報數,數到m的那個人又出列;依此規律重複下去,直到圓桌周圍的人全部出列。
ListNode* JosepRing(ListNode* list, int k)//刪除第K個結點,把這個結點的data改成下一個結點的data,然後刪除第K個結點的下一個結點。
{
if (!list)
{
return NULL;
}
ListNode* cur = list;
while (cur->next != cur)
{
int count = k;
while (--count)
{
cur = cur->next;
}
ListNode* next = cur->next;
cur->data = next->data;
free(next);
}
return cur;
}
6.逆置/反轉單鏈表
ListNode* Reverse(ListNode* list)
{
ListNode* newlist = NULL;
ListNode* cur = list;
while (cur)
{
//摘結點
ListNode* tmp = cur;
cur = cur->next;
//插結點
tmp->next = newlist;
newlist = tmp;
}
return newlist;
}
7.單鏈表排序(冒泡排序)
void BubbleSort(ListNode* list)
{
ListNode* tail = NULL;
while (list->next != tail)
{
ListNode* cur = list;
ListNode* next = cur->next;
while (next != tail)
{
if (cur->data > next->data)
{
Datetype tmp = cur->data;
cur->data = next->data;
next->data = tmp;
}
cur = cur->next;
next = next->next;
}
tail = cur;
}
}
8.合併兩個有序鏈表,合併後依然有序
ListNode* Merge(ListNode* list1, ListNode* list2)
{
if (!list1)
{
return list2;
}
if (!list2)
{
return list1;
}
//先找出兩個鏈表中小的一個結點,把它摘下來做新鏈表的頭結點
ListNode* list = NULL;
if (list1->data < list2->data)
{
list = list1;
list1 = list1->next;
}
else
{
list = list2;
list2 = list2->next;
}
//尾插
ListNode* tail = list;
while (list1&&list2)
{
if (list1->data < list2->data)
{
tail->next = list1;
list1 = list1->next;
}
else
{
tail->next = list2;
list2 = list2->next;
}
tail = tail->next;
}
if (!list1)
{
tail->next = list2;
}
if (!list2)
{
tail->next = list1;
}
return list;
}
9.查找單鏈表的中間節點,要求只能遍歷一次鏈表
ListNode* FindMidNode(ListNode* list)
{
if (!list)
{
return NULL;
}
ListNode* slow = list;
ListNode* fast = list;
while (fast&&fast->next)
{
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
10.查找單鏈表的倒數第k個節點,要求只能遍歷一次鏈表
ListNode* FindTail_k_Node(ListNode* list,int K)
{
ListNode* slow = list;
ListNode* fast = list;
while (--K)
{
if (fast == NULL)//fast爲空說明K值大於鏈表長度。既K值無效
{
return NULL;
}
fast = fast->next;
}
while (fast->next)
{
slow = slow->next;
fast = fast->next;
}
return slow;
}