1.比较顺序表和链表的优缺点,说说它们分别在什么场景下使用?
顺序表:连续空间
随机访问比较快,创建也简单
插入删除比较麻烦。
链表: 非联系空间
插入删除比较方便
查找访问比较麻烦,需要遍历
2.从尾到头打印单链表
void PrintTailToHead(ListNode *pList) //逆序打印 用递归
{
if (pList == NULL)
return;
PrintTailToHead(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);
}
4.在无头单链表的一个节点前插入一个节点
void InsertPosFront(ListNode *pos, DataType x) //在无头单链表的一个节点前插入一个节点
{
assert(pos);
//1.创建节点
ListNode * newNode = InitList(pos->data);
newNode->next=pos->next;
pos->next=newNode;
//2.交换值
pos->data=x;
}
5.单链表实现约瑟夫环
ListNode* JoseohRing(ListNode *pList, int k)//约瑟夫环
{
if(pList==NULL)
return NULL;
//牢记这是一个环
ListNode *cur = pList;
while (cur->next!=cur)
{
int count = k;
while (--count)//走k-1次
{
cur=cur->next;
}
//这样就相当于删除后面的,
ListNode *next=cur->next;
cur->data=next->data;
cur->next=next->next;
free(next);
//这样子删除把之前的节点给搞丢了
/*
ListNode *next=cur->next;
free(cur);
cur=next;*/
}
return cur;
}
6.逆置/反转单链表
ListNode* Reverse(ListNode *pList)//链表的逆置 重新洗牌链表 所以需要返回一个新的头
{
//空表或者只有一个节点的表
if ((pList == NULL) || (pList->next == NULL))
return pList;
else
{
ListNode *cur = pList;
ListNode *NewHeade=NULL;
//注意这里的逻辑
while (cur)
{
ListNode *tmp = cur;
cur = cur->next;
tmp->next=NewHeade;
NewHeade=tmp;
}
return NewHeade;
}
}
7.单链表排序(冒泡排序&快速排序)
void BubbleSort(ListNode *plist)
{
assert(plist);
ListNode *tail=NULL;
while (tail!=plist)
{
int exchange = 0;
ListNode *cur=plist;
ListNode *next=cur->next;
while (next!=tail)
{
if(cur->data>next->data)
{
int tmp=cur->data;
cur->data=next->data;
next->data=tmp;
exchange = 1;
}
cur=cur->next;
next=next->next;
}
if(exchange==0)
return;
tail=cur;
}
}
8.合并两个有序链表,合并后依然有序
ListNode* MergeList(ListNode *pList1, ListNode *pList2)//归并排序
{
if (pList1 == NULL)
return pList2;
else if (pList2 == NULL)
return pList1;
else
{
//摘头结点
ListNode* list=NULL;
if (pList2->data < pList1->data)
{
//注意这里的赋值
list=pList2;
pList2=pList2->next;
}
else
{
list=pList1;
pList1=pList1->next;
}
//注意是改变指向 而不是重新开辟 这里还需要思考
ListNode *tmp=list;
while (pList1&&pList2)
{
if (pList1->data>pList2->data)
{
tmp->next=pList2;
pList2=pList2->next;
}
else
{
tmp->next=pList1;
pList1=pList1->next;
}
tmp=tmp->next;
}
if (pList1)
{
tmp->next=pList1;
}
else
{
tmp->next=pList2;
}
return list;
}
}
9.查找单链表的中间节点,要求只能遍历一次链表
ListNode* FindMidNode(ListNode *pList)//查找单链表的中间节点
{
//注意prev指针 这个非常必要
ListNode *fast = pList;
ListNode *slow = pList;
ListNode *prev = pList;
while (fast&&fast->next)
{
prev=slow;
slow=slow->next;
fast=fast->next->next;
}
if (fast==NULL)
{
slow=prev;
}
return slow;
}
10.查找单链表的倒数第k个节点,要求只能遍历一次链表
ListNode* FindTailkNode(ListNode *pList, DataType k)//查找单链表的倒数第k个节点
{
ListNode *fast = pList;
ListNode *slow = pList;
ListNode *prev = pList;
while (--k)
{
fast=fast->next;
}
//画图有助于理解
while (fast->next)
{
slow=slow->next;
fast=fast->next;
}
return slow;
}
C语言经典面试题(基础题)
最新推荐文章于 2024-07-31 09:00:00 发布