单链表中的常见算法问题(剑指offer5/13/15/16/17)
2014-04-12 23:39
218 查看
1.单链表的结点
2.创建链表
3.删除链表
4.遍历输出链表(从表头到表尾)
5.链表的长度
6.链表逆置
7.O(1)时间删除一个指定结点
8.输出单链表中的倒数第K个结点的值
9.合并两个排序的链表
测试代码
注:部分代码参考自剑指offer
struct ListNode { int m_nKey; ListNode* m_pNext; };
2.创建链表
ListNode* createList(int length) { //创建表头结点 ListNode* head = new ListNode(); head->m_pNext = NULL; ListNode* p = head; int value = 0; //临时存储用户键入的第i个结点值 for (int i = 0; i < length; ++i) { cout << "ListNode" << i << ":\t"; cin >> value; //将新创建的结点插入链表中 ListNode* q = new ListNode(); q->m_nKey = value; q->m_pNext = NULL; p->m_pNext = q; p = q; } return head; }
3.删除链表
void deleteList(ListNode* head) { if (NULL == head) { return; } ListNode* p = head; ListNode* q = p; while (p->m_pNext) { q = p; p = p->m_pNext; delete q; q = NULL; } delete head; head = NULL; }
4.遍历输出链表(从表头到表尾)
void showList(ListNode* head) { //如果是空链表直接退出 if (NULL == head) return; ListNode* p = head->m_pNext; while (p != NULL) { cout << p->m_nKey << "\t"; p = p->m_pNext; } cout << endl; }
5.链表的长度
int listLength(ListNode* head) { if (NULL == head) { return 0; } int length = 0; ListNode*p = head->m_pNext; while (NULL != p) { p = p->m_pNext; ++length; } return length; }
6.链表逆置
ListNode* listReverse(ListNode* sourceHead) { if (NULL == sourceHead) return NULL; ListNode* newHead = new ListNode(); newHead->m_pNext = NULL; ListNode* p = NULL; //中间结点 while (sourceHead->m_pNext != NULL) { //将原来链表的第一个结点从链表中删除 p = sourceHead->m_pNext; sourceHead->m_pNext = p->m_pNext; //将删除掉的结点以头插法插入到新的链表中 p->m_pNext = newHead->m_pNext; newHead->m_pNext = p; } return newHead; }
7.O(1)时间删除一个指定结点
void deleteListNode(ListNode* pHeadListNode, ListNode* pToBeDeleted) { if (NULL == pHeadListNode || NULL == pToBeDeleted) { return; } //方法二:在保证链表中包含待删除结点的前提下,将待删除结点的下一个结点值 //替换掉要删除结点的值,然后删除待删除结点的下一个结点 //如果待删除结点是链表中的唯一结点 ListNode* pHeadNext = pHeadListNode->m_pNext; if (pHeadNext == pToBeDeleted && pHeadNext == NULL) { delete pToBeDeleted; pToBeDeleted = NULL; pHeadNext = NULL; } //如果要删除的结点不是最后一个结点,且待删除的链表的长度大于1 else if (pToBeDeleted->m_pNext != NULL) { ListNode* pDeletedNext = pToBeDeleted->m_pNext; pToBeDeleted->m_nKey = pDeletedNext->m_nKey; pToBeDeleted = pDeletedNext->m_pNext; delete pDeletedNext; } //如果待删除结点是链表的末尾结点(也是最常见的操作方法) else { //方法一:找到要删除结点,用其前一个结点指向其下一个结点,从而达到删除的目的 ListNode* p = pHeadListNode; ListNode* q = pHeadListNode->m_pNext; while (q != pToBeDeleted && q != NULL) { p = q; q = q->m_pNext; } if (q != NULL) { p->m_pNext = q->m_pNext; } } }
8.输出单链表中的倒数第K个结点的值
int findLastKNodeValue(ListNode* head, const unsigned int k) { if (NULL == head || k <= 0) { return -1; } //计数器 unsigned int count = 0; ListNode* p = head; ListNode* q = head; //如果链表长度多于k,则q先遍历k个值 while (count < k && q != NULL) { q = q->m_pNext; ++count; } //如果少于k直接退出 if (NULL == q) { return -1; } //如果链表的结点多于k个,两个指针一起遍历到先遍历指针为NULL时 while (NULL != q) { q = q->m_pNext; p = p->m_pNext; } //当链表长度多于k时,输出倒数第k个结点的值 return p->m_nKey; }
9.合并两个排序的链表
ListNode* mergeSortedLinkedList(ListNode* head1, ListNode* head2) { //有个链表为空时返回另外一个链表即可--代码的鲁棒性 if (NULL == head1) { return head2; } if (NULL == head2) { return head1; } //合并后的新头 结点 ListNode* head = new ListNode(); head->m_pNext = NULL; ListNode* s = head; while (NULL != head1->m_pNext && NULL != head2->m_pNext) { ListNode* p = head1->m_pNext; ListNode* q = head2->m_pNext; if (p->m_nKey < q->m_nKey) { head1->m_pNext = p->m_pNext; p->m_pNext = s->m_pNext; s->m_pNext = p; s = p; } else { head2->m_pNext = q->m_pNext; q->m_pNext = s->m_pNext; s->m_pNext = q; s = q; } } while (NULL != head1->m_pNext) { ListNode* p = head1->m_pNext; head1->m_pNext = p->m_pNext; p->m_pNext = s->m_pNext; s->m_pNext = p; s = p; } while (NULL != head2->m_pNext) { ListNode* q = head2->m_pNext; head2->m_pNext = q->m_pNext; q->m_pNext = s->m_pNext; s->m_pNext = q; s = q; } return head; }
测试代码
/* * * Created on: 2014-3-20 16:16:52 * Author: danDingCongRong */ #include<iostream> using namespace std; int main() { int listLen = 0; cout << "输入链表的长度:\t"; cin >> listLen; ListNode* head = createList(listLen); cout << "原始链表:" << endl; showList(head); cout << "链表的长度为:" << listLength(head) << endl; ListNode* newHead = listReverse(head); cout << "逆置后的链表:" << endl; cout << "" << endl; showList(newHead); cout << "倒数第5个数是:" << endl; cout << findLastKNodeValue(newHead, 5) << endl; ListNode* head1 = createList(listLen); cout << "原始链表:" << endl; showList(head1); ListNode* head2 = createList(listLen); cout << "原始链表:" << endl; showList(head2); cout << "合并两个有序的链表:" << endl; ListNode* head3 = mergeSortedLinkedList(head1, head2); showList(head3); cout << "链表的长度为:" << listLength(head3) << endl; return 0; }
注:部分代码参考自剑指offer
相关文章推荐
- 剑指offer-算法题练习:part16 链表中倒数第k个结点
- 剑指offer_面试题15_链表中倒数第k个节点(考虑问题要全面)
- 剑指offer-算法题练习:part17 反转链表
- 剑指offer-15:单链表有趣问题-有环-环长度-环入口等(续)
- 剑指offer之面试题15-3:链表的中间结点
- 剑指Offer16翻转链表
- 【剑指offer】面试题15:链表中倒数第k个结点
- 【剑指offer-Java版】16反转链表
- 剑指offer-算法题练习:part18 合并两个排序的链表
- 剑指Offer-15-链表中的倒数第k个节点
- 剑指Offer面试题16(Java版):翻转链表
- 剑指Offer 17 合并两个排序的链表
- 剑指Offer16:反转链表
- 剑指offer--面试题13:在O(1)时间删除链表节点
- 剑指offer-16:反转链表
- 剑指offer-16:反转链表(单链表逆序)
- 【剑指Offer学习】【面试题16 :反转链表】
- 【剑指offer-解题系列(15)】反转链表
- 【剑指offer】3.4代码的鲁棒性——面试题16:反转链表
- 剑指offer-面试题13-在O(1)时间删除链表节点