最近在补充和提高数据结构及算法方面的知识,对于链表操作有些感悟,特此记录下来。
一般的链表生成、插入、去除等基本操作没什么好说的,只是在做两个有序链表合成一个的题目时感觉有些吃力。花了很长时间外加调试终于磕磕碰碰把它做完后,问了自己一个问题是,如果原始链表是乱序的呢? 那就先排序呗。 没想到的是,链表排序比数组排序要复杂N倍。 指针飞来飞去的,很容易把脑子搞糊涂。虽然最后独自完成了,但过程蛮痛苦,也发现自己对于链表的复杂操作比较薄弱,缺乏练习。打击人啊 :)
总结几点感悟:
1)链表是数据结构基础中的基础,尤其在复杂些的非线性数据结构中,如树,图, 基本上都是写链表操作。 所以多花些力气把链表操作尤其是复杂操作练熟还是很有帮助的。我以前就对它不是很重视,总以为应用很少。。。
2) 无论是基本操作还是复制操作,都要动手去实现它。 试问自己一下,能不看任何资料、准确无误快速的写一个链表生成的代码吗?起码我以前是不行,这东西只有多练过几次才熟练。
3)在链表基本操作中,如删除或添加某节点, 我们总是先从Head节点for循环遍历到目标节点的前继节点,然后在进行相应的操作。 但是在链表的sort或merge的复杂操作中, 需要定义额外的指针来实时记录目标节点的前继节点。 所以在这类操作中,对于单个链表,往往定义额外的4、5指针,有的用于遍历原始链表、有的用于实时记录前继节点、有的用于比较节点值大小。。。
4)在链表排序中,一般地有两种思路,一是不停的遍历原始链表找出最大或最小值的节点,然后remove再依次插到新的链表中;另一是从头结点开始遍历链表,将找到的最大或最小的节点和头节点交换,然后从第二个节点开始遍历找到第二个最大值,并和第二个节点进行交换,依次类推。。。 从这里可以看出,这两种思路的基础是 选择排序法,而不是bubble sort。
废话少说,附上算法实现源代码。欢迎指正。。。
第一种思路
static void RemoveNode(LINK_NODE *pFront, LINK_NODE *pRemove, LINK *ppLinkList)
610 {
611 if (pFront == pRemove)
612 {
613 *ppLinkList = (*ppLinkList)->pNextNode;
614 }
615 else
616 {
617 pFront->pNextNode = pRemove->pNextNode;
618 }
619 printf("remove value is %d \n", pRemove->index);
620 }
621
622 static void InsertNode(LINK *ppInsertFront, LINK_NODE *pInsert, LINK *ppNewList)
623 {
624 if (*ppInsertFront == NULL)
625 {
626 *ppNewList = pInsert;
627 *ppInsertFront = pInsert;
628 }
629 else
630 {
631 (*ppInsertFront)->pNextNode = pInsert;
632 *ppInsertFront = (*ppInsertFront)->pNextNode;
633 }
634 }
635
636 void SortLinkList(LINK_NODE *pList, LINK *ppNewList)
637 {
638 LINK_NODE *pOrignNode, *pNewNode;
639 LINK_NODE *pRemoveNode, *pFrontNode;
640 LINK_NODE *pInsertFront;
641
642 pOrignNode = pNewNode = pList;
643 pRemoveNode = pFrontNode = pOrignNode;
644 pInsertFront = NULL;
645
646 while (pOrignNode)
647 {
648 while (pOrignNode->pNextNode)
649 {
650 if (pOrignNode->pNextNode->index < pRemoveNode->index)
651 {
652 pFrontNode = pOrignNode;
653 pRemoveNode = pOrignNode->pNextNode;
654 }
655 pOrignNode = pOrignNode->pNextNode;
656 }
657 RemoveNode(pFrontNode, pRemoveNode, &pList);
658 InsertNode(&pInsertFront, pRemoveNode, ppNewList);
659
660 pOrignNode = pFrontNode = pList;
661 pRemoveNode = pOrignNode;
662 }
663 pInsertFront = NULL;
664 }
第二种思路
static void SwitchNode(LINK_NODE *pFront1, LINK_NODE *pNode1, LINK_NODE *pFront2, LINK_NODE *pNode2, LINK *ppNewList)
667 {
668 LINK_NODE *pTempNode;
669
670 if (pFront1 == pFront2)
671 return;
672
673 if (pNode1 == pFront2)
674 {
675 pFront1->pNextNode = pNode2;
676 pTempNode = pNode2->pNextNode;
677 pNode2->pNextNode = pNode1;
678 pNode1->pNextNode = pTempNode;
679 return;
680 }
681
682 if (pFront1 == pNode1)
683 {
684 *ppNewList = pNode2;
685 }
686 else
687 {
688 pFront1->pNextNode = pNode2;
689 }
690
691 pTempNode = pNode2->pNextNode;
692 pNode2->pNextNode = pNode1->pNextNode;
693
694 pFront2->pNextNode = pNode1;
695 pNode1->pNextNode = pTempNode;
696 }
697
698 void SelectSortList(LINK_NODE *pList, LINK *ppNewList)
699 {
700 LINK_NODE *pNode1, *pNode2;
701 LINK_NODE *pFront1, *pFront2;
702 LINK_NODE *pMaxNode;
703
704 pNode1 = pNode2 = pList;
705 pFront1 = pFront2 = pList;
706
707 while (pNode1)
708 {
709 pMaxNode = pNode1;
710 while (pNode2->pNextNode)
711 {
712 if (pNode2->pNextNode->index > pMaxNode->index)
713 {
714 pFront2 = pNode2;
715 pMaxNode = pNode2->pNextNode;
716 }
717 pNode2 = pNode2->pNextNode;
718 }
719 SwitchNode(pFront1, pNode1, pFront2, pMaxNode, ppNewList);
720 pFront1 = pMaxNode;
721 pNode1 = pMaxNode->pNextNode;
722 pNode2 = pNode1;
723 }
724 }