1.判断单链表是否带环
2.计算环的长度
3.求环的入口
4.判断两个链表是否相交,若相交求交点(默认链表不带环)
5.判断两个链表是否相交,若相交求交点(链表可能带环)
6.找两个已排序链表的相同部分
7.复杂链表拷贝
判断单链表是否带环
方法一:将每个节点保存到顺序表中,再将每个节点遍历,看是否带环。
但是这种方法的时间复杂度为O(n^2),所以,又想出了一种方法,来优化第一种方法,来使时间复杂度变为O(n)
方法二:创建两个指针分别为fast和slow,让这两个指针开始都指向链表头部,让fast指针每次走两步,slow指针每次走一步,若最终两个指针相遇,则链表一定带环。
696 //判断单链表是否带环
697 LinkNode* LinkListHasCricle(LinkNode* head)
698 {
699 if(head == NULL)
700 {
701 //空链表
702 return NULL;
703 }
704 LinkNode* fast=head;
705 LinkNode* slow=head;
706 while(fast!=NULL&&fast->next!=NULL)
707 {
708 fast=fast->next->next;
709 slow=slow->next;
710 if(fast==slow)
711 {
712 return slow;
713 }
714 }
715 return NULL;
716 }
717
计算环的长度
定义一个指针cur,和一个长度len,让cur指针刚开始就指向环的相遇点,让cur指针一直往下走,cur每走一步len都加1,当再次回到相遇点,返回len,就是环的长度。
718 //计算环的长度
719 size_t LinkListCricleLen(LinkNode* head)
720 {
721 if(head == NULL)
722 {
723 //空链表
724 return 0;
725 }
726 LinkNode* meet_node=LinkListHasCricle(head);
727 if(meet_node == NULL)
728 {
729 return 0;
730 }
731 LinkNode* cur=meet_node->next;
732 size_t len=1;
733 while(cur!=meet_node)
734 {
735 cur=cur->next;
736 len++;
737 }
738 return len;
739 }
740
求环的入口
结论:从链表开始点到入口点的长度等于入口点到相遇点的长度
741 //求环的入口
742 LinkNode* LinkListCricleEntry(LinkNode* head)
743 {
744 if(head == NULL)
745 {
746 //空链表
747 return NULL;
748 }
749 LinkNode* meet_node=LinkListHasCricle(head);
750 if(meet_node == NULL)
751 {
752 return NULL;
753 }
754 LinkNode* cur1=head;
755 LinkNode* cur2=meet_node;
756 while(cur1!=cur2)
757 {
758 cur1=cur1->next;
759 cur2=cur2->next;
760 }
761 return cur1;
762 }
763
判断两个链表是否相交,若相交求交点(默认链表不带环)
两条链表相交有两种可能,一种为“X”型相交,一种为“Y”型相交,但由于链表的每一个节点的下一个节点只能有一个,所以“X”型相交不成立,只有“Y”型相交成立。
(1)判断是否相交
对于“Y”型相交,判断是否相交,需要先定义两个指针cur1和cu2分别指向两个链表的头部,然后分别往后移动,直到cur1和cur2都指向链表的尾部,若最终两个指针cur1=cur2,则说明,链表相交。
764 //判断两个链表是否相交(链表不带环)
765 int LinkListHasCross(LinkNode* head1,LinkNode* head2)
766 {
767 if(head1 == NULL||head2 == NULL)
768 {
769 //空链表
770 return 0;
771 }
772 LinkNode* cur1=head1;
773 LinkNode* cur2=head2;
774 for(;cur1->next!=NULL;cur1=cur1->next);
775 for(;cur2->next!=NULL;cur2=cur2->next);
776 return cur1 == cur2?1:0;
777 }
(2)若相交,求交点
首先要定义两个指针cur1和cur2,使它们指向两个链表的头部,然后计算出两条链表的长度,分别为len1和len2,若两个长度不相等,则设两个长度差为offset,让长的链表的的cur指针先走offset步,然后就相当于两个cur指针在同一起点出发,然后让cur1和cur2每次走一步,直到cur1=cur2,则相等的点就是交点。
779 //接上一问题:若相交,求交点
780 LinkNode* LinkListCrossPos(LinkNode* head1,LinkNode* head2)
781 {
782 size_t len1=LinkListSize(head1);
783 size_t len2=LinkListSize(head2);
784 LinkNode* cur1=head1;
785 LinkNode* cur2=head2;
786 if(len1>len2)
787 {
788 size_t i=0;
789 for(;i<len1-len2;++i)
790 {
791 cur1=cur1->next;
792 }
793 }
794 else
795 {
796 size_t i=0;
797 for(;i<len2-len1;++i)
798 {
799 cur2=cur2->next;
800 }
801 while(cur1!=NULL&&cur2!=NULL)
802 {
803 if(cur1 == cur2)
804 {
805 return cur1;
806 }
807 cur1=cur1->next;
808 cur2=cur2->next;
809 }
810 return NULL;
811 }
812 }
813
判断两个链表是否相交,若相交求交点(链表可能带环)
(1)判断链表是否带环
这个问题分为了几种情况,分别为
1.两个链表都不带环 ——方法同上
2.两个链表一个带环,一个不带环 ——一定不相交
3.两个链表都带环
1)不相交
2)相交
a)交点在环外
b)交点在环上
思路:
分别求两个链表环的入口,若两个链表都不带环,则用上面的方法,若有一个链表带环,一个不带环,则直接返回不相交,若两个链表都带环,若两个链表环的入口相同,则是环外相交,若从第一个入口出发绕环一周能到达第二个入口点,则是环内相交,若都不是以上情况,则直接返回不相交。
814 //两个链表是否相交(可能带环)
815 int LinkListHasCrossWithCircle(LinkNode* head1,LinkNode* head2)
816 {
817 //分别求两个链表的入口
818 LinkNode* entry1=LinkListCricleEntry(head1);
819 LinkNode* entry2=LinkListCricleEntry(head2);
820 //(1)若两个链表都不带环,则用上面的方法
821 if(entry1 == NULL && entry2 == NULL)
822 {
823 return LinkListHasCross(head1,head2);
824 }
825 //(2)若有一个带环,一个不带环,则返回不相交
826 if((entry1 == NULL && entry2!=NULL)||(entry1!=NULL && entry2 == NULL))
827 {
828 return 0;
829 }
830 //(3)若两个都带环
831 //1)若入口点重合,说明环外相交
832 if(entry1 == entry2)
833 {
834 return 1;
835 }
836 //2)若从一个入口点出发,绕环一周能到达第二个入口点,则说明是环内相交
837 LinkNode* cur=entry1->next;
838 while(cur!=entry1)
839 {
840 if(cur == entry2)
841 {
842 return 1;
843 }
844 cur=cur->next;
845 }
846 //3)若以上两种情况都不是,则不相交
847 return 0;
848 }
849
(2)若相交,求交点
若是两个环相交,分为环外相交和环内相交。
1)环外相交:两个环环外相交,则说明只有一个入口点,将入口点设为结束标记,转化为两条不带环链表“Y”字形相交问题
2)环内相交:求出两个入口点,就是交点
850 //接上一问题:若相交,求交点(环外相交)
851 LinkNode* LinkListCrossWithCirclePos(LinkNode* head1,LinkNode* head2)
852 {
853 LinkNode* longlist=NULL;
854 LinkNode* shortlist=NULL;
855 LinkNode* cur1=head1;
856 LinkNode* cur2=head2;
857 int count1=0;
858 int count2=0;
859 int gap=0;
860 LinkNode* meet_node=LinkListHasCricle(head1);
861 while(cur1!=meet_node)
862 {
863 count1++;
864 cur1=cur1->next;
865 }
866 while(cur2!=meet_node)
867 {
868 count2++;
869 cur2=cur2->next;
870 }
871 longlist=head1;
872 shortlist=head2;
873 if(count1<count2)
874 {
875 longlist=head2;
876 shortlist=head1;
877 }
878 gap=abs(count1-count2);
879 while(gap--)
880 {
881 longlist=longlist->next;
882 }
883 while(shortlist!=longlist)
884 {
885 shortlist=shortlist->next;
886 longlist=longlist->next;
887 }
888 return shortlist;
889 }
找两个已排序链表的相同部分
890 //找两个已排序链表的相同部分(默认每个链表中不包含连续相同的元素,如2333333)
891 LinkNode* LinkListUnionSet(LinkNode* head1,LinkNode* head2)
892 {
893 LinkNode* cur1=head1;
894 LinkNode* cur2=head2;
895 LinkNode* new_head=NULL;
896 LinkNode* new_tail=NULL;
897 while(cur1!= NULL && cur2!=NULL)
898 {
899 if(cur1->data<cur2->data)
900 {
901 cur1=cur1->next;
902 }
903 else if(cur1->data>cur2->data)
904 {
905 cur2=cur2->next;
906 }
907 else{ //cur1=cur2
908 if(new_head==NULL)
909 {
910 new_head=new_tail=CreateNode(cur1->data);
911 cur1=cur1->next;
912 cur2=cur2->next;
913 }
914 else{
915 new_tail->next=CreateNode(cur2->data);
916 new_tail=new_tail->next;
917 cur1=cur1->next;
918 cur2=cur2->next;
919 }
920 //cur1=cur1->next;
921 //cur2=cur2->next;
922
924 //return new_head;
925 }
926 return new_head;
927 }
928
复杂链表拷贝
方法一:先按照简单链表的方式拷贝,然后遍历链表,找到找到每个链表节点的random指针相对于链表头部的偏移量,遍历新链表,根据偏移量设新链表的random指针
929 //复杂链表拷贝
930 typedef struct ComplexNode
931 {
932 LinkNodeType data;
933 struct ComplexNode* next;
934 struct ComplexNode* random;
935 }ComplexNode;
936
937 ComplexNode* CreateComplexNode(LinkNodeType value)
938 {
939 ComplexNode* new_node=(ComplexNode*)malloc(sizeof(ComplexNode));
940 new_node->data=value;
941 new_node->next=NULL;
942 new_node->random=NULL;
943 return new_node;
944 }
945
946 size_t Diff(ComplexNode* src,ComplexNode* dst)
947 {
948 size_t offset=0;
949 while(src!=NULL)
950 {
951 if(src == dst)
952 {
953 break;
954 }
955 ++offset;
956 src=src->next;
957 }
958 if(src == NULL)
959 {
960 return(size_t)-1; //是一个特别大的值
961 }
962 }
963
964 ComplexNode* Step(ComplexNode* head,size_t offset)
965 {
966 ComplexNode* cur=head;
967 size_t i=0;
968 while(1)
969 {
970 if(head == NULL)
971 {
972 return NULL;
973 }
974 if(i>=offset)
975 {
976 return cur;
977 }
978 ++i;
979 cur=cur->next;
980 }
981 return NULL;
982 }
983
984 ComplexNode* CopyComplexList(ComplexNode* head)
985 {
986 //先按照简单的链表copy一份
987 ComplexNode* new_head=NULL;
988 ComplexNode* new_tail=NULL;
989 ComplexNode* cur=head;
990 for(;cur!=NULL;cur=cur->next)
991 {
992 ComplexNode* new_node=CreateComplexNode(cur->data);
993 if(new_node == NULL)
994 {
995 new_head=new_tail=new_node;
996 }
997 else{
998 new_tail->next=new_node;
999 new_tail=new_tail->next;
1000 }
1001 }
1002 //遍历链表,找到每个链表节点random指针相对于链表头指针的偏移量
1003 //遍历新链表,根据偏移量设新链表的random指针
1004 ComplexNode* new_cur=new_head;
1005 for(cur=head;cur!=NULL;cur=cur->next,new_cur=new_cur->next)
1006 {
1007
1008 if(cur->random == NULL)
1009 {
1010 new_cur->random = NULL;
1011 continue;
1012 }
1013 //通过Diff函数计算出链表两个节点的偏移量
1014 size_t offset=Diff(head,cur->random);
1015 //通过Step函数,相当于求出从new_head出发,走了offset步到达的位置
1016 new_cur->random;
1017 }
1018 return new_head;
1019
1020 }
1021
方法二:遍历链表,在每个链表后插入新节点,维护新节点的random指针,将新节点拆除
1023 ComplexNode* CopyComplexList2(ComplexNode* head)
1024 {
1025 //遍历链表在每个链表后插入新节点
1026 //维护新节点的random指针
1027 //新节点排除
1028 ComplexNode* cur=head;
1029 for(;cur!=NULL;cur=cur->next->next)
1030 {
1031 ComplexNode* new_node=CreateComplexNode(cur->data);
1032 new_node->next=cur->next;
1033 }
1034 for(cur=head;cur!=NULL;cur=cur->next->next)
1035 {
1036 ComplexNode* new_cur=cur->next;
1037 if(cur->random==NULL)
1038 {
1039 new_cur->random=NULL;
1040 continue;
1041 }
1042 new_cur->random=cur->random->next;
1043 }
1044 ComplexNode* new_head=NULL;
1045 ComplexNode* new_tail=NULL;
1046 for(cur=head;cur!=NULL;cur=cur->next)
1047 {
1048 ComplexNode* new_cur=cur->next;
1049 cur->next=new_cur->next;
1050 if(new_head == NULL)
1051 {
1052 new_head=new_tail=new_cur;
1053 }
1054 else{
1055 new_tail->next=new_cur;
1056 new_tail=new_tail->next;
1057 }
1058 new_tail=NULL;
1059 }
1060 return new_head;
1061 }