链表经典题目合集(c语言版)
链表作为数据结构中较为热门的类型,一直是各大公司笔试面试常考类型,同时链表也有很多经典题目,可以帮助初学者更好的理解链表。
1.从尾到头打印链表
先遍历链表,遍历的同时将链表的值头插进一个新的链表,在打印新的链表即可。
void SLitsPrintTailToHead(SListNode* pHead) { SListNode* _new, *ptr; _new = NULL; ptr = pHead; while (ptr) { SListPushFront(&_new, ptr->data); ptr = ptr->next; } while (_new) { printf("%d ", _new->data); _new = _new->next; } }
2.删除一个无头单链表的非尾节点(不能遍历链表)
假设删除的是pos节点,我们可以将pos的下一个节点的数据存入pos节点,在删除pos节点的下一个节点即可。
void SListDelNonTailNode(SListNode* pos) { SListNode* Ppos; Ppos = NULL; Ppos = pos->next; pos->data = Ppos->data; pos->next = Ppos->next; free(Ppos); }
3.
在无头单链表的一个节点前插入一个节点(不能遍历链表)
假设我们需要在pos前插入一个节点,我们可以先在pos后插入一个与pos数据一样的节点,在将pos的数据改为给的值。
void SListInsertFrontNode(SListNode* pos, DataType x) { SListNode* _new; _new = NULL; _new = BuySListNode(pos->data); _new->next = pos->next; pos->next = _new; pos->data = x; }
4.
单链表实现约瑟夫环(JosephCircle)
约瑟夫环
是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依
此
规律重复下去,直到圆桌周围的人全部出列。通常解决这类问题时我们把编号从0~n-1,最后
结果+1即为原问题的解。
先不断迭代找到尾节点,让尾节点的next指针指向头节点,这样形成了一个环,接着进入循环,循环的结束条件为只剩一个节点。不断地迭代k次然后删除当前节点。
SListNode* SListJosephCircle(SListNode* pHead, int k) { SListNode* str, *tail; int i = 0; str = pHead; tail = pHead; while (tail->next) { tail = tail->next; } tail->next = pHead; while (str->next!=str) { for (;i < k;++i) { str = str->next; } str->data = str->next->data; str->next = str->next->next; free(str->next); } return str; }
5.
逆置/反转单链表
遍历链表,同时将数据头插入链表,新的链表为反转链表。
SListNode* SListReverse(SListNode* list) { SListNode* _new, *str; _new = NULL; str = list; while (str) { SListPushFront(&_new, str->data); str = str->next; } return _new; }6.单链表冒泡排序
void SListBubbleSort(SListNode* list) { int i, j,count; count = 0; int mid; SListNode* str,*ptri,*ptrj; str = list; while (str) { str = str->next; count++; } for (i = 0;i < count-1;i++) { ptri = list; ptri = ptri->next; for (j = 0;j < i-1;j++) { ptrj = list; ptrj = ptrj->next; if (ptri->data > ptrj->data) { mid = ptri->data; ptri->data = ptrj->data; ptrj->data = mid; } } } }
7.
合并两个有序链表,合并后依然有序
给两个指针分别指向两个有序链表,两个链表所指向的数据进行比大小,小的插入新链表并且指针向后走,进行下一次比较,当两个指针都走完时结束。
SListNode* SListMerge(SListNode* list1, SListNode* list2) { SListNode* str1, *str2,*_new; str1 = list1; str2 = list2; _new = NULL; while (str1&&str2) { if (str1->data > str2->data) { SListPushBack(&_new,str2->data); str2 = str2->next; } if (str1->data < str2->data) { SListPushBack(&_new, str1->data); str1 = str1->next; } else { SListPushBack(&_new, str2->data); } } return _new; }
8.
查找单链表的中间节点,要求只能遍历一次链表
给两个指针,第一个指针走一步时第二个指针走两步,当快指针走完时慢指针走到中间节点。
SListNode* SListFindMidNode(SListNode* list) { SListNode* fast, *slow; fast = list; slow = list; while (fast->next) { fast = fast->next; if (fast->next == NULL) { break; } fast = fast->next; slow = slow->next; } return slow; }
9.
查找单链表的倒数第k个节点,要求只能遍历一次链表
同样定义两个指针,快指针先走k步慢指针开始走,当快指针走完时慢指针走到倒数第K个节点。
SListNode* SListFindTailKNode(SListNode* list, size_t k) { SListNode* fast, *slow; fast = list; slow = list; int i; for (i = 0;i < k;i++) { fast = fast->next; } while (fast) { fast = fast->next; slow = slow->next; } return slow; }
扫描二维码关注公众号,回复:
53180 查看本文章
10.构造一个带环链表
找到环入口的节点,让尾节点指向入口节点。
SListNode* SListIsCycle(SListNode* list) { SListNode* str,*ptr; str = list; ptr = SListFind(list, 0); while (str) { str = str->next; } str->next = ptr; return ptr; }
11.求环的长度
定义两个快慢指针,快指针走两步慢指针走一步,当他们在环里相遇时结束。再让他们继续走,第二次相遇时快指针一定比慢指针快了环的长度步。
int SListCycleLen(SListNode* meetNode) { int len,count1,count2; SListNode*fast, *slow; fast = meetNode->next; slow = meetNode; int count=1; while (fast!=slow) { fast = fast->next->next; slow = slow->next; } slow - slow->next; while (slow != fast) { slow = slow->next; count++; } return count; }