1.比较顺序表和链表的优缺点,说说它们分别在什么场景下使用?
顺序表
优点 | 缺点 |
---|---|
存储密度高 | 容易浪费内存 |
随机存取节点 | 插入删除效率低 |
单链表
优点 | 缺点 |
---|---|
插入删除效率高 | 访问效率低 |
节点动内存利用率高 |
适用场景
顺序表 | 单链表 |
---|---|
数据量小,删除和插入工作量小的 | 数据量大,删除和插入比较频繁的 |
2.从尾到头打印单链表
这个题采用递归的思想:
void reverse_print(ListNode* pList)
{
ListNode* tmp = pList;
if (tmp == NULL)
{
return;
}
else
{
reverse_print(pList->next);
printf("%d", tmp->data);
}
}
3.删除一个无头单链表的非尾节点
采用替换法,可以将下一个节点的数据复制至已知节点,就有两个节点,然后删除后一个。
void NoHeadList(ListNode** ppList)
{
if ((*ppList)->next == NULL)
{
return;
}
ListNode* tmp = (*ppList)->next;
(*ppList)->data = (*ppList)->next->data;
(*ppList)->next = (*ppList)->next->next;
free(tmp);
}
4.在无头单链表的一个节点前插入一个节点
与上一个题思路相同
void PushNoHaed(ListNode** ppList, DataType x)
{
//创建新节点
ListNode* node = (ListNode*)malloc(sizeof(ListNode));
node->data = x;
node->next = NULL;
//已知节点复制
node->next = (*ppList)->next;
(*ppList)->next = node;
node->data = (*ppList)->data;
(*ppList)->data = x;
}
5.单链表实现约瑟夫环
循环删除第几个节点,直至剩下一个。
ListNode* Josephus(ListNode* ppList, int x)
{
ListNode* cru = ppList;
while (cru != cru->next)
{
int count = x;
while (--count)
{
cru = cru->next;
}
ListNode* next = cru->next;
cru->data = next->data;
cru->next = next->next;
free(next);
}
return cru;
}
6.逆置/反转单链表
ListNode* ReverseList(ListNode* ppList)
{
ListNode* NewHead = NULL;
ListNode* cru = ppList;
ListNode* p1 = ppList;
while (cru)
{
cru = cru->next;
p1->next=NewHead;
NewHead = p1;
p1 = cru;
}
return NewHead;
}
7.单链表排序(冒泡排序&快速排序)
void Bubblsort(ListNode** pplist)
{
ListNode* Tail = NULL;
while (Tail!=(*pplist)->next)
{
int count = 0;
ListNode* slow = *pplist;
ListNode* fast = slow->next;
while (fast != Tail)
{
if (slow->data > fast->data)
{
DataType tmp = slow->data;
slow->data = fast->data;
fast->data = tmp;
count++;
}
slow = fast;
fast = slow->next;
}
Tail = slow;
if (count == 0)
break;
}
}
8.合并两个有序链表,合并后依然有序
ListNode* combineList(ListNode *p1, ListNode* p2)
{
ListNode* NewList = NULL;
ListNode* tmp = NULL;
if (p1 == NULL)
return p2;
else if (p2 == NULL)
return p1;
else
{
if (p1->data<=p2->data)
{
NewList = p1;
p1 = p1->next;
}
else
{
NewList = p2;
p2 = p2->next;
}
tmp = NewList;
while (p1&&p2)
{
if (p1->data > p2->data)
{
NewList->next = p1;
p1 = p1->next;
NewList = NewList->next;
}
else
{
NewList->next = p2;
p2 = p2->next;
NewList = NewList->next;
}
}
if (p1 == NULL)
{
NewList->next = p2;
}
else
{
NewList->next = p1;
}
}
return tmp;
}
9.查找单链表的中间节点,要求只能遍历一次链表
用两个指针,一个是另一个的二倍,当快指针到达最后,慢指针到达中间。
ListNode* Findmid(ListNode* pList)
{
ListNode* slow = pList;
ListNode* fast = pList;
while (fast != NULL)
{
slow = slow->next;
if (fast->next == NULL)
break;
fast = fast->next->next;
}
return slow;
}
10.查找单链表的倒数第k个节点,要求只能遍历一次链表
ListNode* Findknode(ListNode* pList, int k)
{
ListNode* slow = pList;
ListNode* fast = pList;
while (k--)
{
fast = fast->next;
}
while (fast != NULL)
{
slow = slow->next;
fast = fast->next;
}
return slow;
}