单链表的实现(点击打开链接)
单链表简易实现后有如下面试题
1.比较顺序表和链表的优缺点,说说它们分别在什么场景下使用?
2.从尾到头打印单链表
3.删除一个无头单链表的非尾节点
4.在无头单链表的一个节点前插入一个节点
5.单链表实现约瑟夫环
6.逆置/反转单链表
7.单链表排序(冒泡排序&快速排序)
8.合并两个有序链表,合并后依然有序
9.查找单链表的中间节点,要求只能遍历一次链表
10.查找单链表的倒数第k个节点,要求只能遍历一次链表
1.比较顺序表和链表的优缺点,说说它们分别在什么场景下使用?
顺序表:内存中地址连续
长度不可变更
支持随机查找 可以在O(1)内查找元素
适用于需要大量访问元素的 而少量增添/删除元素的程序
链表 :内存中地址非连续
长度可以实时变化
不支持随机查找 查找元素时间复杂度O(n)
适用于需要进行大量增添/删除元素操作 而对访问元素无要求的程序
结构体的定义
typedef int DataType;
typedef struct ListNode
{
DataType data;
struct ListNode *next;
}ListNode;
2.从尾到头打印单链表
函数实现
void TaliToHead(ListNode *plist) //从尾到头打印单链表
{
if(plist == NULL)
return;
TaliToHead(plist->next);
printf("%d->",plist->data);
}
3.删除一个无头单链表的非尾节点
void DeleteNoHead(ListNode **pos) //删除一个无头单链表的非尾节点
{
ListNode * cur = *pos;
ListNode *prel = cur;
while(cur->next) //从该节点从前往后覆盖,并删除最后一个节点
{
prel = cur;
cur->data = (cur->next)->data;
cur = cur->next;
}
free(prel->next);
prel->next = NULL;
}
4.在无头单链表的一个节点前插入一个节点
void InsertNoHead(ListNode **pos, DataType x) //无头单链表的一个节点前插入一个节点
{
ListNode *cur = *pos;
ListNode *ptemp = BuyNode(x);
assert(*pos);
ptemp->next = cur->next;
cur->next = ptemp;
ptemp->data = cur->data;
cur->data = x;
}
5.单链表实现约瑟夫环
void JosephRing(ListNode **pplist,DataType x) //约瑟夫环,x为间隔
{
ListNode *cur = *pplist;
ListNode *prel = *pplist;
ListNode *ptem = NULL;
if(NULL == *pplist || NULL == (*pplist)->next)
return;
while(cur->next)
{
cur = cur->next;
}
cur->next = prel; //将单链表的首尾节点连起来成环。
cur = *pplist;
while(cur->next!=cur)
{
DataType n = x;
while(n--)
{
prel = cur;
cur = cur->next;
}
prel->next = cur->next;
free(cur);
cur = prel->next;
}
printf("%d\n",cur->data); //最后剩下的节点
}
6.逆置/反转单链表
void ReverseList(ListNode **pplist) //逆序单链表
{
ListNode *cur = *pplist;
ListNode *ptemp = NULL;
ListNode *ret = NULL;
if(NULL == *pplist || NULL == (*pplist)->next)
return;
while(cur)
{
ptemp = cur;
cur = cur->next;
ptemp->next = ret;
ret = ptemp;
}
*pplist = ret;
}
7.单链表排序(冒泡排序&快速排序)
void SortList(ListNode *plist) //冒泡排序单链表
{
ListNode *tail = NULL;
if(NULL == plist || NULL == (plist)->next)
return;
while(plist->next != tail)
{
ListNode *cur = plist;
ListNode *next = cur->next;
while(next != tail)
{
if(cur->data < next->data)
{
DataType temp = cur->data;
cur->data = next->data;
next->data = temp;
}
cur = next;
next = next->next;
}
tail = cur;
}
}
8.合并两个有序链表,合并后依然有序
void ListToList(ListNode **pplist,ListNode **pplist1) //合并两个单链表
{
ListNode *cur = *pplist;
if(NULL == cur)
{
cur = *pplist1;
}
else
{
while(cur->next)
cur = cur->next;
cur->next = *pplist1;
}
}
合并后再用一个上面的排序函数即可
9.查找单链表的中间节点,要求只能遍历一次链表
ListNode *MidOfList(ListNode *plist) //查找中间节点
{
ListNode *fast = plist; //快指针一次过两个节点
ListNode *slow = plist; //慢指针一次过一个,快指针到尾节点,慢指针就到中间节点
if(NULL == plist || NULL == plist->next)
return plist;
else
{
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
}
}
return slow;
}
10.查找单链表的倒数第k个节点,要求只能遍历一次链表
和上面找中间相似
ListNode *FindNum(ListNode *plist,DataType x) //查找单链表中倒数第x个节点
{
ListNode *fast = plist;
ListNode *slow = plist;
if(NULL == plist || NULL == plist->next)
return plist;
while(x--) //快指针先跑x个节点
{
fast = fast->next;
}
while(fast && fast->next) //快指针到尾节点是,慢指针刚好到倒数第X个节点
{
slow = slow->next;
fast = fast->next;
}
return slow;
}
以上函数为简单思路,有待优化和提升,测试过没什么大问题,有大问题联系我。。
