1.比较顺序表和链表的优缺点,说说它们分别在什么场景下使用?
优缺点
顺序表和链表:
1.每个元素的访问 顺序表内存访问时,不需要多次内存到缓存的步骤,链表每个节点都需要指针找到内存然后加载到缓存中.
2.头插.头删.中间位置 顺序表在插入和删除之前要先对后面的数据进行挪动 ,链表直接插入和删除节点 .
3.尾插.尾删 顺序表直接对数据进行操作,链表需要对空间进行操作.
4.空间 操作 顺序表 一次性开辟好空间,增容时直接增加两个空间,链表造成空间浪费|每一次对节点大小进行操作,不会造成空间浪费.
2.从尾到头打印单链表
遍历一次链表,从后先前打印,使用递归的思想
void PrintfListReverse(ListNode *plist)
{
if(plist==NULL)
{
return;
}
PrintfListReverse(plist->next);
printf("<-%d",plist->data);
}
3.删除一个无头单链表的非尾节点
删除无头单链表的非尾节点是无法找点前一个节点的信息,只能通过目标节点的下一个节点的信息赋值给自己然后删除下一个节点,从而达到删除自己的目的
void EraseNonTail(ListNode* pos) //删除无头链表的非尾节点
{
if((pos==NULL)&&(pos->next==NULL))
{
return ;
}
else
{
ListNode* cur=pos->next;
pos->next=cur->next;
pos->data=cur->data;
free(cur);
cur=NULL;
}
}
4.在无头单链表的一个节点前插入一个节点
思想:先找到pos然后在pos后面插入一个tmp节点,插入后将tmp节点和pos节点互换位置,从而达到在一个无头链表的一个节点前插入一个节点。
代码实现如下:
void AddNoHeadTail(ListNode* pos,Datatype x)//无头链表非头节点前插入一个节点
{
ListNode *tmp=NULL;
assert(pos);
tmp=BuyNode(x);
tmp->next=pos->next;
pos->next=tmp;
tmp->data=pos->data;
pos->data=x;
}
5.单链表实现约瑟夫环
首先讲一个故事:
**据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。
代码实现如下:
ListNode* JosephRing(ListNode *plist,Datatype k) //单链表实现约瑟夫环
{
ListNode *cur=plist;
ListNode *pos=plist;
if(plist==NULL)
{
return NULL;
}
while(pos->next)
{
pos=pos->next;
}
pos->next=plist;
while(cur->next!=cur)
{
Datatype n=k;
while(n--)
{
pos=cur;
cur=cur->next;
}
pos->next=cur->next;
free(cur);
cur=pos->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.单链表排序(冒泡排序&快速排序)
冒泡排序算法的运作如下:
1.比较相邻的元素。如果第一个比第二个大,就交换他们两个。
2.对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
3.针对所有的元素重复以上的步骤,除了最后一个。
4.持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
代码实现:
void BubbleSort(ListNode *list) //冒泡排序单链表
{
ListNode *pos=NULL;
ListNode *next=NULL;
ListNode *Tail=NULL;
if((list==NULL)&&(list->next==NULL))
{
return ;
}
while(list->next!=Tail)
{
pos=list;
next=pos->next;
while(Tail!=next)
{
if(pos->data > next->data)
{
Datatype tmp=pos->data;
pos->data=next->data;
next->data=tmp;
}
pos=pos->next;
next=next->next;
}
Tail=pos;
}
}
8.合并两个有序链表,合并后依然有序
代码实现:
ListNode * Merge(ListNode* list1,ListNode *list2)//合并两个有序链表,合并后依然有序
{
if(list1==NULL)
{
return list2;
}
if(liat2==NULL)
{
return list1;
}
ListNode *list=list1;
if(list2->data < list1->data)
{
list=list2;
list2=list2->next;
}
else
{
list=list1;
list1=list1->next;
}
ListNode* tail=list;
while(list1&&list2)
{
if(list1->data < list2->data)
{
tail->next=list1;
list1=list->next;
}
else
{
tail->next=list2;
list2=list2->next;
}
tail=tail->next;
}
if(list1)
{
tail->next=list1;
}
else
{
tail->next=list2;
}
return list;
}
9.查找单链表的中间节点,要求只能遍历一次链表
代码实现:
ListNode * FindMidNode(ListNode * list)//查找单链表的中间节点,要求只遍历一次
{
if(list==NULL)
{
return NULL;
}
ListNode *slow=list,*fast=list;
while(fast&&fast->next)
{
slow=slow->next;
fast=fast->next->next;
}
return slow;
}
10.查找单链表的倒数第k个节点,要求只能遍历一次链表
代码实现:
ListNode * FindTailkNode(ListNode * list,int k)//查找单链表的倒数第k个节点,只遍历一次
{
ListNode * slow=list;
ListNode * fast=list;
while(k--)
{
if(fast==NULL)
{
return NULL;
}
fast=fast->next;
}
while(fast)
{
slow=slow->next;
fast=fast->next;
}
return slow;
}