C语言实现单链表面试题--基础篇

来源:互联网 发布:mac看照片怎么下一张 编辑:程序博客网 时间:2024/06/05 14:55
1.从尾到头打印单链表
2.删除一个无头单链表的非尾节点
3.在无头单链表的一个节点前插入一个节点
4.单链表实现约瑟夫环
5.逆置/反转单链表
6.单链表排序(冒泡排序)
7.合并两个有序链表,合并后依然有序
8.查找单链表的中间节点,要求只能遍历一次链表

9.查找单链表的倒数第k个节点,要求只能遍历一次链表


函数如下:

typedef int DataType;typedef struct ListNode{DataType data;ListNode* next;}ListNode;

void PrintList_r(ListNode* pplist);//1.逆序打印void EraseNonTail(ListNode* pos); //2.删除一个无头单链表的非尾节点 void InsertNonHead(ListNode* pos, DataType data); //3.在无头单链表的一个节点前插入一个节点 ListNode* JosephRing(ListNode* plist, int k);//4.约瑟夫环,数到k删掉(参数是一个循环链表)ListNode* ReverseList(ListNode* plist);//5.单链表逆序存储(摘节点)void BubbleList(ListNode* plist); //6.冒泡排序ListNode* CombineList(ListNode* plist1, ListNode* plist2);//7.合并两个有序链表,合并后依然有序ListNode* SearchListMid(ListNode* plist); //8.查找中间节点(偶数个节点返回靠后的中间节点)ListNode* SearchListK_r(ListNode* plist, int k); //9.查找单链表的倒数第k个节点,要求只能遍历一次链表






1.从尾到头打印单链表

思路:递归

void PrintList_r(ListNode* plist){if (plist == NULL){return;}PrintList_r (plist -> next);printf("%d->", plist -> data);}






2.删除一个无头单链表的非尾节点

思路:交换当前节点和下一个节点的值,释放掉下一个节点

void EraseNonTail(ListNode* pos){assert(pos && pos->next);ListNode* next = pos->next;pos->data = next->data;pos->next = next->next;free(next);}





3.在无头单链表的一个节点前插入一个节点

思路:在该位置后面插入一个节点,并与该节点交换值

void InsertNonHead(ListNode* pos, DataType data){assert(pos);ListNode* next = pos->next;ListNode* tmp = BuyNode(data);pos->next = tmp;tmp->next = next;DataType datatmp = pos->data;pos->data = tmp->data;tmp->data = datatmp;}




4.单链表实现约瑟夫环

思路:每次数到k的时候删除该节点,直到只剩一个,并返回该节点

ListNode* JosephRing(ListNode* plist, int k){//如果不带环返回空指针,判断是否带环的函数进阶篇有写if(IsCycle(plist) == NULL){return NULL;}ListNode* cur = plist;//只剩一个节点循环停止while(cur != cur->next){int count = k;while(--count)//例如k为3的时候,只用走2步{cur = cur->next;}//替换法删除ListNode* next = cur->next;cur->data = next->data;cur->next = next->next;free(next);}return cur;}





5.逆置单链表

思路:创建一个新的头指针,用cur和tmp摘节点,每次把原链表的头结点指向新的头结点

ListNode* ReverseList(ListNode* plist){ListNode* newhead = NULL;ListNode* cur = plist;ListNode* tmp = plist;while(cur){cur = cur->next;tmp->next = newhead;newhead = tmp;tmp = cur;}return newhead;}





6.单链表排序(冒泡排序)

单趟:用cur和next控制,符合条件则交换,当next走到NULL时第一趟结束
多趟:用tail标记链表尾部,当tail为第二个节点时,交换全部完成

void BubbleList(ListNode* plist){ListNode* tail = NULL;while(tail != plist->next){ListNode* cur = plist;ListNode* next = plist->next;while(next != tail){if(cur->data > next->data){DataType tmp = cur->data;cur->data = next->data;next->data = tmp;}next = next->next;cur = cur->next;}tail = cur;}}






7.合并两个有序链表,合并后依然有序 

思路:定义一个新的头指针,一开始指向plist1和plist2首元素较小的那个,然后依次遍历两个链表,每次把较小的值加到新头指针list的后面

ListNode* CombineList(ListNode* plist1, ListNode* plist2){ListNode* list = NULL;if(plist1 == NULL){return plist2;}else if(plist2 == NULL){return plist1;}else{if(plist1->data < plist2->data){list = plist1;plist1 = plist1->next;}else{list = plist2;plist2 = plist2->next;}ListNode* tail = list;while (plist1 && plist2){if(plist1->data < plist2->data){tail->next = plist1;plist1 = plist1->next;tail = tail->next;}else{tail->next = plist2;plist2 = plist2->next;tail = tail->next;}}if(plist1 == NULL){tail->next = plist2;}else{tail->next = plist1;}}return list;}






8.查找单链表的中间节点,要求只能遍历依次链表

思路:快慢指针,每次快指针走2步,慢指针走1步

1.链表有奇数个节点,快指针指向最后一个节点,慢指针则指向中间节点

2.链表有偶数个节点,快指针指向空(tail->next),慢指针则指向两个中间节点靠后的那一个

ListNode* SearchListMid(ListNode* plist){ListNode* fast = plist;ListNode* slow = plist;while (fast && fast->next){fast = (fast->next)->next;slow = slow->next;}return slow;}






9.查找单链表的倒数第k个节点,要求只能遍历依次链表

思路:快慢指针,快指针先走k-1步,然后快慢指针一起一步一步的走,当快指针走到尾节点时,慢指针则指向倒数第k个节点

ListNode* SearchListK_r(ListNode* plist, int k){ListNode* fast = plist;ListNode* slow = plist;//fast往后走k-1步int i = k;for(i=0; i<k-1; i++){fast = fast->next;//如果k大于了链表长度,返回空指针if(fast == NULL){return NULL;}}//让fast走到最后一个节点while(fast->next){fast = fast->next;slow = slow->next;}return slow;}






原创粉丝点击