链表

来源:互联网 发布:全国电子地图矢量数据 编辑:程序博客网 时间:2024/05/05 01:07

单链表

目录

1.单链表反转

2.找出单链表的倒数第4个元素

3.找出单链表的中间元素

4.删除无头单链表的一个节点

5.两个不交叉的有序链表的合并

6.有个二级单链表,其中每个元素都含有一个指向一个单链表的指针。

写程序把这个二级链表称一级单链表。

7.单链表交换任意两个元素(不包括表头)

8.判断单链表是否有环?如何找到环的“起始”点?如何知道环的长度?

9.判断两个单链表是否相交

10.两个单链表相交,计算相交点

11.用链表模拟大整数加法运算

12.单链表排序

13.删除单链表中重复的元素


这些题目在面试中经常出现,所以在这个专题中总结一下,

我所使用的代码都是C/C++。

会写一些思路,这样就不必看代码了。

冰冻三尺,非一日之寒,让我们慢慢来练习吧。


链表的节点定义如下:

[cpp] view plaincopyprint?
  1. struct node
  2. {
  3. char val;
  4. node * next;
  5. };

用结构体定义,而不是用类。

从使用的方便来说,类要更好一些,

但是为了和其他关于链表的地方保持一致还是使用了结构体来定义。

节点元素为char型,是为了输出和调试方便。


注:这些题目都是前人总结的。


总结:

1,使用指针时,一定要检查指针是否为空;

2,要考虑特殊情况,如指针为空,空链表(只有表头结点),只有一个结点等;

3,插入,删除,交换等操作时都需要使用当前结点的前驱,需要同时记录下来;

4,单链表有无环以及交叉链表求相交结点的两个题目有很大的联系,

也是经常考的题目,有些题目可以转化成这类题目;

5,递归思想很重要,在链表的倒序输出,反转,模拟大数相交,

快速排序中都有用到,分治算法往往需要用递归来做;

6,快慢指针的思想很重要,常数时间删除结点的算法也很考察智力。

 

题目:

顾名思义,就是反转一个单链表。

思路1:

重新开辟内存,简历一个新链表,然后从后面往前面复制。

由于单链表无法很容易得到当前节点前面的节点,所以,复制每一个节点都得从前往后找到该节点,

单个节点复制的时间复杂度为O(n),整个复杂度则为O(n^2),空间复杂度为O(n)。不可取。

思路2:

不开辟新内存,采用交换节点内容的方式。

前后两个指针,相互交换内容,之后前面的指针后移,后面的指针前移,再交换。

问题是后面指针前移的时间复杂度依然是O(n),所以时间复制度不变,仍为O(n^2)。不可取。

思路3,:

改变指针指向。时间复杂度为O(n),空间复杂度为O(1)。

注意:

输入可能为:

1,NULL

2,空链表,即只含有表头结点

3,单一结点,只有一个有效结点

4,多个结点

前三种情况都不需要处理。

反转当前结点pNode时,需要记录下一个结点pNext,且需要当前结点的上一个结点preNode。

第一个结点的反转比较特殊,初始化这些指针即可,且将第一结点的next置NULL。

结束之后,所有结点处理完了。加上表头结点即可。

注意:

有表头结点。


[cpp] view plaincopyprint?
  1. // LinkTable.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include "stdafx.h"
  4. #include <iostream>
  5. #include <string>
  6. using namespace std;
  7. //链表的结构体
  8. struct node
  9. {
  10. char val;
  11. node * next;
  12. };
  13. //1.单链表反转
  14. struct node * create( string & str_link )
  15. {
  16. int len = str_link.length();
  17. struct node * phead =new node(); //带有表头的链表,表头中不存储任何元素
  18. struct node * preNode = phead;
  19. for( int i=0; i<len; i++ )
  20. {
  21. struct node * pNode =new node();
  22. pNode->val = str_link[i];
  23. pNode->next = NULL;
  24. preNode->next = pNode;
  25. preNode = pNode;
  26. }
  27. return phead;
  28. }
  29. void out_link( struct node * phead )
  30. {
  31. if( phead == NULL )
  32. return;
  33. struct node * pNode = phead->next;
  34. while( pNode )
  35. {
  36. cout <<pNode->val;
  37. pNode = pNode->next;
  38. }
  39. cout << endl;
  40. }
  41. void reverse_link(struct node * phead )
  42. {
  43. if( !phead || !phead->next || !phead->next->next )//无链表,空链表,当个节点链表则返回
  44. return;
  45. //处理第一个节点
  46. struct node * preNode = phead->next;
  47. struct node * pNode = preNode->next;
  48. preNode->next = NULL;
  49. //从第二个节点开始处理
  50. while(pNode)
  51. {
  52. struct node * pNext = pNode->next;
  53. pNode->next = preNode;
  54. preNode = pNode;
  55. pNode = pNext;
  56. }
  57. //加上表头节点
  58. phead->next = preNode;
  59. }
  60. void reverse_test()
  61. {
  62. string str;
  63. cin >> str;
  64. struct node *phead = create( str );
  65. out_link( phead );
  66. reverse_link( phead );
  67. out_link( phead );
  68. }
  69. int _tmain(int argc, _TCHAR* argv[])
  70. {
  71. reverse_test();
  72. return 0;
  73. }


 

注意:

无论采用什么思路,编程时都要考虑,链表结点个数不足4个的情况。


思路1:

先找到最后一个元素,然后再从头扫描一遍,判断该元素的之后的第三个结点是否是最后一个结点。O(4n)=O(n)。比较粗糙的方法。


思路2:

快慢指针。先让快指针先走4步,找到第四个结点。然后让快慢指针同时走,每次一步。当快指针走到最后一个结点时,慢指针指向倒数第4个元素。


思路3:

建立一个含有4个元素的循环队列(数组来模拟),扫描一遍队列,让他们不断的进入循环队列中,当最后一个结点进入循环队列后,队列的下一个元素则是倒数第4个结点。


我采用思路2来实现。


[cpp] view plaincopyprint?
  1. // LinkTable.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include "stdafx.h"
  4. #include <iostream>
  5. #include <string>
  6. using namespace std;
  7. //链表的结构体
  8. struct node
  9. {
  10. char val;
  11. node * next;
  12. };
  13. //2,找第4个结点
  14. struct node * create( string & str_link )
  15. {
  16. int len = str_link.length();
  17. struct node * phead =new node(); //带有表头的链表,表头中不存储任何元素
  18. struct node * preNode = phead;
  19. for( int i=0; i<len; i++ )
  20. {
  21. struct node * pNode =new node();
  22. pNode->val = str_link[i];
  23. pNode->next = NULL;
  24. preNode->next = pNode;
  25. preNode = pNode;
  26. }
  27. return phead;
  28. }
  29. void out_link( struct node * phead )
  30. {
  31. if( phead == NULL )
  32. return;
  33. struct node * pNode = phead->next;
  34. while( pNode )
  35. {
  36. cout <<pNode->val;
  37. pNode = pNode->next;
  38. }
  39. cout << endl;
  40. }
  41. struct node * find_third_node(struct node * phead )
  42. {
  43. if( !phead ) return NULL;
  44. //快指针先走4步
  45. struct node *pFast = phead;
  46. struct node *pSlow = phead;
  47. int num =4;
  48. while(num--)
  49. {
  50. pFast = pFast->next;
  51. if(!pFast) //还没走完就没了
  52. {
  53. return NULL;
  54. break;
  55. }
  56. }
  57. //快慢指针一起走
  58. while(pFast)
  59. {
  60. pFast = pFast->next;
  61. pSlow = pSlow->next;
  62. }
  63. return pSlow;
  64. }
  65. void test()
  66. {
  67. string str;
  68. cin >> str;
  69. struct node *phead = create( str );
  70. cout << "The Link is : ";
  71. out_link( phead );
  72. struct node *pNode = find_third_node( phead );
  73. if( pNode )
  74. cout << "The last_third node's value is : " << pNode->val <<endl;
  75. else
  76. cout << "The number of node is less than 4." << endl;
  77. }
  78. int _tmain(int argc, _TCHAR* argv[])
  79. {
  80. test();
  81. return 0;
  82. }

问题:

找出单链表的中间元素


思路:

快慢指针。

快指针每次走两步,慢指针每次走1步。快指针走到头时,慢指针所指即为中间结点。

如果结点个数N为偶数,则中间结点为第N/2个结点。


[cpp] view plaincopyprint?
  1. // LinkTable.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include "stdafx.h"
  4. #include <iostream>
  5. #include <string>
  6. using namespace std;
  7. //链表的结构体
  8. struct node
  9. {
  10. char val;
  11. node * next;
  12. };
  13. //2,找第4个结点
  14. struct node * create( string & str_link )
  15. {
  16. int len = str_link.length();
  17. struct node * phead =new node(); //带有表头的链表,表头中不存储任何元素
  18. struct node * preNode = phead;
  19. for( int i=0; i<len; i++ )
  20. {
  21. struct node * pNode =new node();
  22. pNode->val = str_link[i];
  23. pNode->next = NULL;
  24. preNode->next = pNode;
  25. preNode = pNode;
  26. }
  27. return phead;
  28. }
  29. void out_link( struct node * phead )
  30. {
  31. if( phead == NULL )
  32. return;
  33. struct node * pNode = phead->next;
  34. while( pNode )
  35. {
  36. cout <<pNode->val;
  37. pNode = pNode->next;
  38. }
  39. cout << endl;
  40. }
  41. struct node * find_mid_node(struct node * phead )
  42. {
  43. if( !phead ) return NULL;
  44. //快慢指针
  45. struct node *pFast = phead;
  46. struct node *pSlow = phead;
  47. int count = 1;
  48. while(pFast)
  49. {
  50. pFast = pFast->next;
  51. if( (count++)%2 ==0 )
  52. pSlow = pSlow->next;
  53. }
  54. return pSlow;
  55. }
  56. void test()
  57. {
  58. string str;
  59. cin >> str;
  60. struct node *phead = create( str );
  61. cout << "The Link is : ";
  62. out_link( phead );
  63. struct node *pNode = find_mid_node( phead );
  64. if( pNode )
  65. cout << "The mid node's value is : " << pNode->val <<endl;
  66. }
  67. int _tmain(int argc, _TCHAR* argv[])
  68. {
  69. test();
  70. return 0;
  71. }


 

问题:

一个单链表,很长,遍历一遍很慢,我们仅知道一个指向某节点的指针pNode,而我们又想删除这个节点。


思路:

将该结点的下一个结点的内容拷贝到当前结点,然后删除下一个结点。

如果该结点时最后一个结点,则必须遍历一遍单链表,找到前面一个结点,然后删掉该结点。


 

注意:

虽然最后一种情况是线性复杂度的,但是总体上来看还是常数时间的。


[cpp] view plaincopyprint?
  1. // LinkTable.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include "stdafx.h"
  4. #include <iostream>
  5. #include <string>
  6. using namespace std;
  7. //链表的结构体
  8. struct node
  9. {
  10. char val;
  11. node * next;
  12. };
  13. //2,找第4个结点
  14. struct node * create( string & str_link )
  15. {
  16. int len = str_link.length();
  17. struct node * phead =new node(); //带有表头的链表,表头中不存储任何元素
  18. struct node * preNode = phead;
  19. for( int i=0; i<len; i++ )
  20. {
  21. struct node * pNode =new node();
  22. pNode->val = str_link[i];
  23. pNode->next = NULL;
  24. preNode->next = pNode;
  25. preNode = pNode;
  26. }
  27. return phead;
  28. }
  29. void out_link( struct node * phead )
  30. {
  31. if( phead == NULL )
  32. return;
  33. struct node * pNode = phead->next;
  34. while( pNode )
  35. {
  36. cout <<pNode->val;
  37. pNode = pNode->next;
  38. }
  39. cout << endl;
  40. }
  41. struct node * find_third_node(struct node * phead )
  42. {
  43. if( !phead ) return NULL;
  44. //快指针先走4步
  45. struct node *pFast = phead;
  46. struct node *pSlow = phead;
  47. int num =4;
  48. while(num--)
  49. {
  50. pFast = pFast->next;
  51. if(!pFast) //还没走完就没了
  52. {
  53. return NULL;
  54. break;
  55. }
  56. }
  57. //快慢指针一起走
  58. while(pFast)
  59. {
  60. pFast = pFast->next;
  61. pSlow = pSlow->next;
  62. }
  63. return pSlow;
  64. }
  65. struct node * find_last_node(struct node * phead )
  66. {
  67. struct node *pNode = phead;
  68. while(pNode->next)
  69. {
  70. pNode = pNode->next;
  71. }
  72. return pNode;
  73. }
  74. void delete_node(struct node * phead, struct node * pNode )
  75. {
  76. if( !phead ) return;
  77. //如果pNode是最后一个结点,则找到前面一个结点
  78. if( !pNode->next )
  79. {
  80. struct node *preNode = phead;
  81. while(phead)
  82. {
  83. if(preNode->next==pNode)
  84. break;
  85. else
  86. preNode = preNode->next;
  87. }
  88. if( !preNode )
  89. {
  90. cout <<"The node is not in the link list" << endl;
  91. return;
  92. }
  93. preNode->next = NULL;
  94. delete pNode;
  95. }
  96. else //否则拷贝下一个元素的内容,并删除下一个结点
  97. {
  98. struct node * pNext = pNode->next;
  99. pNode->val = pNext->val;
  100. pNode->next = pNext->next;
  101. delete pNext;
  102. }
  103. }
  104. void test()
  105. {
  106. string str;
  107. cin >> str;
  108. struct node *phead = create( str );
  109. cout << "The Link is : ";
  110. out_link( phead );
  111. struct node *pNode = find_third_node(phead);
  112. delete_node( phead, pNode );
  113. cout << "delete the last third node:" <<endl;
  114. out_link( phead );
  115. pNode = find_last_node(phead);
  116. delete_node( phead, pNode );
  117. cout << "delete last node: "<<endl;
  118. out_link( phead );
  119. }
  120. int _tmain(int argc, _TCHAR* argv[])
  121. {
  122. test();
  123. return 0;
  124. }

思路:

比较大小,控制指针指向,如果一个链表已经结束,则把剩下的链表加上去即可。


注意:

要判断输入时候正确。

两个链表是否为空链表等特殊情况。


如果交叉了怎么办。后面会介绍。


[cpp] view plaincopyprint?
  1. // LinkTable.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include "stdafx.h"
  4. #include <iostream>
  5. #include <string>
  6. using namespace std;
  7. //链表的结构体
  8. struct node
  9. {
  10. char val;
  11. node * next;
  12. };
  13. //2,找第4个结点
  14. struct node * create( string & str_link )
  15. {
  16. int len = str_link.length();
  17. struct node * phead =new node(); //带有表头的链表,表头中不存储任何元素
  18. struct node * preNode = phead;
  19. for( int i=0; i<len; i++ )
  20. {
  21. struct node * pNode =new node();
  22. pNode->val = str_link[i];
  23. pNode->next = NULL;
  24. preNode->next = pNode;
  25. preNode = pNode;
  26. }
  27. return phead;
  28. }
  29. void out_link( struct node * phead )
  30. {
  31. if( phead == NULL )
  32. return;
  33. struct node * pNode = phead->next;
  34. while( pNode )
  35. {
  36. cout <<pNode->val;
  37. pNode = pNode->next;
  38. }
  39. cout << endl;
  40. }
  41. struct node * merge_link( struct node * phead1, struct node * phead2 )
  42. {
  43. if( !phead1 || !phead1->next)return phead2;
  44. if( !phead2 || !phead2->next)return phead1;
  45. struct node * phead = phead1;
  46. struct node * pNode = phead;
  47. struct node * pNode1 = phead1->next;
  48. struct node * pNode2 = phead2->next;
  49. delete phead2;
  50. while( pNode1 && pNode2)
  51. {
  52. if( pNode1->val <= pNode2->val )
  53. {
  54. pNode->next = pNode1;
  55. pNode1 = pNode1->next;
  56. }
  57. else
  58. {
  59. pNode->next = pNode2;
  60. pNode2 = pNode2->next;
  61. }
  62. pNode = pNode->next;
  63. }
  64. if( pNode2 )
  65. pNode->next = pNode2;
  66. if( pNode1 )
  67. pNode->next = pNode1;
  68. return phead;
  69. }
  70. void test()
  71. {
  72. string str;
  73. cin >> str;
  74. struct node *phead1 = create( str );
  75. cin >> str;
  76. struct node *phead2 = create( str );
  77. struct node * phead = merge_link( phead1, phead2 );
  78. cout << "after merge: "<<endl;
  79. out_link( phead );
  80. }
  81. int _tmain(int argc, _TCHAR* argv[])
  82. {
  83. test();
  84. return 0;
  85. }

思路:

有两种情况,相邻和不相邻。

首先找两个节点的前驱,可以通过前驱来判断是否相邻。

相邻则改变3个结点的next指针,不相邻则改变4个结点的next指针。

注意:

要判断许多出错的情况,比如,结点不在表中,结点为空,表为空等。


[cpp] view plaincopyprint?
  1. // LinkTable.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include "stdafx.h"
  4. #include <iostream>
  5. #include <string>
  6. using namespace std;
  7. //链表的结构体
  8. struct node
  9. {
  10. char val;
  11. node * next;
  12. };
  13. //建立链表
  14. struct node * create( string & str_link )
  15. {
  16. int len = str_link.length();
  17. struct node * phead =new node(); //带有表头的链表,表头中不存储任何元素
  18. struct node * preNode = phead;
  19. for( int i=0; i<len; i++ )
  20. {
  21. struct node * pNode =new node();
  22. pNode->val = str_link[i];
  23. pNode->next = NULL;
  24. preNode->next = pNode;
  25. preNode = pNode;
  26. }
  27. return phead;
  28. }
  29. //输出链表
  30. void out_link( struct node * phead )
  31. {
  32. if( phead == NULL )
  33. return;
  34. struct node * pNode = phead->next;
  35. while( pNode )
  36. {
  37. cout <<pNode->val;
  38. pNode = pNode->next;
  39. }
  40. cout << endl;
  41. }
  42. //找到第index个元素
  43. struct node * find_node(struct node* phead,int index )
  44. {
  45. if(!phead) return NULL;
  46. struct node * pNode = phead;
  47. while( index--)
  48. {
  49. pNode = pNode->next;
  50. if( !pNode )
  51. return NULL;
  52. }
  53. return pNode;
  54. }
  55. //找前驱节点
  56. struct node* find_preNode(struct node* phead, struct node* pNode)
  57. {
  58. if( !pNode ) return NULL;
  59. struct node* preNode = phead;
  60. while( preNode )
  61. {
  62. if( preNode->next == pNode )
  63. return preNode;
  64. preNode = preNode->next;
  65. }
  66. return NULL;
  67. }
  68. //交换节点
  69. void exchange_node(struct node* phead, struct node* pNode1,struct node* pNode2)
  70. {
  71. if( !phead ) return;
  72. //分别找到pNode1的前驱pPre1,和pNode2的前驱pPre2
  73. struct node* pPre1 = find_preNode( phead, pNode1);
  74. struct node* pPre2 = find_preNode( phead, pNode2);
  75. if( !pPre1 || !pPre2 )return; //有任何一个没有找到
  76. //相邻的情况
  77. struct node *pBefore, *pAfter, *pPre;
  78. if( pPre2 == pNode1 )
  79. {
  80. pBefore = pNode1;
  81. pAfter = pNode2;
  82. pPre = pPre1;
  83. }
  84. if( pPre1 == pNode2)
  85. {
  86. pBefore = pNode2;
  87. pAfter = pNode1;
  88. pPre = pPre2;
  89. }
  90. if( pPre2 == pNode1 || pPre1 == pNode2 )
  91. {
  92. pPre->next = pAfter;
  93. pBefore->next = pAfter->next;
  94. pAfter->next = pBefore;
  95. }
  96. else
  97. {
  98. //不相邻的情况
  99. struct node *pNext1 = pNode1->next;
  100. pNode1->next = pNode2->next;
  101. pPre1->next = pNode2;
  102. pPre2->next = pNode1;
  103. pNode2->next = pNext1;
  104. }
  105. }
  106. void test()
  107. {
  108. string str;
  109. cin >> str;
  110. struct node *phead = create( str );
  111. int index;
  112. cin >> index;
  113. struct node * pNode1 = find_node( phead, index );
  114. cin >> index;
  115. struct node * pNode2 = find_node( phead, index );
  116. exchange_node( phead, pNode1, pNode2 );
  117. cout << "after exchange: "<<endl;
  118. out_link( phead );
  119. }
  120. int _tmain(int argc, _TCHAR* argv[])
  121. {
  122. test();
  123. return 0;
  124. }

判断单链表是否有环?

思路:

快慢指针,快指针每次走两步,慢指针每次走一步。

每次判断快指针是否到头了以及快慢指针是否指向同一元素。

快指针走到头了,则没有环;

如果快指针和慢指针指向同一个元素,则有环。

如何找到环的起始点?

思路:

如果有环,则快慢指针一定相遇在环上。

将环从快慢指针相遇结点剪开,则变成了两个单链表相交的问题。

设两个单链表的长度分别为N,M,用两个指针分别指向两链表第一个结点,

让位于长链表上的指针先走abs(N-M)步。然后一起走,相遇时则为环的起始点。


如何知道环的长度?

绕一圈即可。

[cpp] view plaincopyprint?
  1. // LinkTable.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include "stdafx.h"
  4. #include <iostream>
  5. #include <string>
  6. using namespace std;
  7. //链表的结构体
  8. struct node
  9. {
  10. char val;
  11. node * next;
  12. };
  13. //建立链表
  14. struct node * create( string & str_link )
  15. {
  16. int len = str_link.length();
  17. struct node * phead =new node(); //带有表头的链表,表头中不存储任何元素
  18. struct node * preNode = phead;
  19. for( int i=0; i<len; i++ )
  20. {
  21. struct node * pNode =new node();
  22. pNode->val = str_link[i];
  23. pNode->next = NULL;
  24. preNode->next = pNode;
  25. preNode = pNode;
  26. }
  27. return phead;
  28. }
  29. //输出链表
  30. void out_link( struct node * phead )
  31. {
  32. if( phead == NULL )
  33. return;
  34. struct node * pNode = phead->next;
  35. while( pNode )
  36. {
  37. cout <<pNode->val;
  38. pNode = pNode->next;
  39. }
  40. cout << endl;
  41. }
  42. //找到第index个元素
  43. struct node * find_node(struct node* phead,int index )
  44. {
  45. if(!phead) return NULL;
  46. struct node * pNode = phead;
  47. while( index--)
  48. {
  49. pNode = pNode->next;
  50. if( !pNode )
  51. return NULL;
  52. }
  53. return pNode;
  54. }
  55. //检查链表有无环
  56. //有,则返回快慢指针共同指向的点
  57. //无,则返回空指针
  58. struct node * check_loop(struct node * phead )
  59. {
  60. if(!phead)
  61. return NULL;
  62. struct node * pFast = phead;
  63. struct node * pSlow = phead;
  64. int step = 1;
  65. while( pFast )
  66. {
  67. pFast = pFast->next;
  68. if( step++%2==0 )
  69. {
  70. pSlow = pSlow->next;
  71. if( pSlow == pFast )
  72. return pSlow;
  73. }
  74. }
  75. return NULL;
  76. }
  77. //求两个节点的距离,即中间有多少个连线
  78. //返回-1为出错,如果是同一节点,则返回0
  79. int find_length( struct node* pNode1,struct node* pNode2 )
  80. {
  81. if(!pNode1||!pNode2) return -1;
  82. int len=0;
  83. while( pNode1 )
  84. {
  85. if( pNode1 == pNode2 )
  86. return len;
  87. pNode1 = pNode1->next;
  88. len++;
  89. }
  90. return -1;
  91. }
  92. //找环的起始点,pTail为快慢指针共同指向的节点
  93. struct node * loop_first_node(struct node * phead, struct node * pTail )
  94. {
  95. if( !phead || !pTail ) return NULL;
  96. struct node * pNode1 = pTail->next;
  97. struct node * pNode2 = phead->next;
  98. int M = find_length( pNode1, pTail );
  99. int N = find_length( pNode2, pTail );
  100. if( M > N )
  101. {
  102. int step = M-N;
  103. while(step--)
  104. pNode1 = pNode1->next;
  105. }
  106. if( N > M )
  107. {
  108. int step = N-M;
  109. while(step--)
  110. pNode2 = pNode2->next;
  111. }
  112. while(pNode1&&pNode2)
  113. {
  114. if(pNode1 == pNode2 )
  115. return pNode1;
  116. pNode1 = pNode1->next;
  117. pNode2 = pNode2->next;
  118. }
  119. return NULL;
  120. }
  121. void test()
  122. {
  123. string str;
  124. cin >> str;
  125. struct node *phead = create( str );
  126. int index;
  127. cin >> index;
  128. struct node * pNode1 = find_node( phead, index );
  129. struct node * pNode = phead;
  130. while( pNode->next )
  131. pNode = pNode->next;
  132. pNode->next = pNode1; //生成有环链表, 注释掉之一行则为无环链表
  133. struct node * pTail = check_loop( phead );
  134. struct node * pFirstLoopNode = NULL;
  135. if( pTail )
  136. {
  137. cout <<"The link has loop." <<endl;
  138. pFirstLoopNode = loop_first_node(phead, pTail);
  139. cout <<"First Loop Node is: " << pFirstLoopNode->val <<endl;
  140. cout <<"The number of node in loop is: " << find_length( pTail->next, pTail)+1 <<endl;
  141. }
  142. else
  143. cout << "The link table has no loop." <<endl;
  144. }
  145. int _tmain(int argc, _TCHAR* argv[])
  146. {
  147. test();
  148. return 0;
  149. }

只介绍O(n)算法

思路1:

将链表1中各结点地址存入HashTable中,

再遍历链表2,如果有结点已经在HashTable中,则两链表相交。


思路2:

将链表1的尾结点和链表2的首结点(注意不是头结点)相连。

再判断是否有环,如果有则两链表相交。


思路3:(最简单的方法)

判断两链表的尾结点是否为同一结点,若是,则相交。

实现部分为思路2。

[cpp] view plaincopyprint?
  1. // LinkTable.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include "stdafx.h"
  4. #include <iostream>
  5. #include <string>
  6. using namespace std;
  7. //链表的结构体
  8. struct node
  9. {
  10. char val;
  11. node * next;
  12. };
  13. //建立链表
  14. struct node * create( string & str_link )
  15. {
  16. int len = str_link.length();
  17. struct node * phead =new node(); //带有表头的链表,表头中不存储任何元素
  18. struct node * preNode = phead;
  19. for( int i=0; i<len; i++ )
  20. {
  21. struct node * pNode =new node();
  22. pNode->val = str_link[i];
  23. pNode->next = NULL;
  24. preNode->next = pNode;
  25. preNode = pNode;
  26. }
  27. return phead;
  28. }
  29. //输出链表
  30. void out_link( struct node * phead )
  31. {
  32. if( phead == NULL )
  33. return;
  34. struct node * pNode = phead->next;
  35. while( pNode )
  36. {
  37. cout <<pNode->val;
  38. pNode = pNode->next;
  39. }
  40. cout << endl;
  41. }
  42. //找到第index个元素
  43. struct node * find_node(struct node* phead,int index )
  44. {
  45. if(!phead) return NULL;
  46. struct node * pNode = phead;
  47. while( index--)
  48. {
  49. pNode = pNode->next;
  50. if( !pNode )
  51. return NULL;
  52. }
  53. return pNode;
  54. }
  55. //检查链表有无环
  56. //有,则返回快慢指针共同指向的点
  57. //无,则返回空指针
  58. struct node * check_loop(struct node * phead )
  59. {
  60. if(!phead)
  61. return NULL;
  62. struct node * pFast = phead;
  63. struct node * pSlow = phead;
  64. int step = 1;
  65. while( pFast )
  66. {
  67. pFast = pFast->next;
  68. if( step++%2==0 )
  69. {
  70. pSlow = pSlow->next;
  71. if( pSlow == pFast )
  72. return pSlow;
  73. }
  74. }
  75. return NULL;
  76. }
  77. //求两个节点的距离,即中间有多少个连线
  78. //返回-1为出错,如果是同一节点,则返回0
  79. int find_length( struct node* pNode1,struct node* pNode2 )
  80. {
  81. if(!pNode1||!pNode2) return -1;
  82. int len=0;
  83. while( pNode1 )
  84. {
  85. if( pNode1 == pNode2 )
  86. return len;
  87. pNode1 = pNode1->next;
  88. len++;
  89. }
  90. return -1;
  91. }
  92. //找环的起始点,pTail为快慢指针共同指向的节点
  93. struct node * loop_first_node(struct node * phead, struct node * pTail )
  94. {
  95. if( !phead || !pTail ) return NULL;
  96. struct node * pNode1 = pTail->next;
  97. struct node * pNode2 = phead->next;
  98. int M = find_length( pNode1, pTail );
  99. int N = find_length( pNode2, pTail );
  100. if( M > N )
  101. {
  102. int step = M-N;
  103. while(step--)
  104. pNode1 = pNode1->next;
  105. }
  106. if( N > M )
  107. {
  108. int step = N-M;
  109. while(step--)
  110. pNode2 = pNode2->next;
  111. }
  112. while(pNode1&&pNode2)
  113. {
  114. if(pNode1 == pNode2 )
  115. return pNode1;
  116. pNode1 = pNode1->next;
  117. pNode2 = pNode2->next;
  118. }
  119. return NULL;
  120. }
  121. void test()
  122. {
  123. string str;
  124. cin >> str;
  125. struct node *phead1 = create( str );
  126. int index;
  127. cin >> index;
  128. struct node * pNode1 = find_node( phead1, index );
  129. cin >> str;
  130. struct node *phead2 = create( str );
  131. struct node * pNode = phead2;
  132. while( pNode->next )
  133. pNode = pNode->next;
  134. pNode->next = pNode1; //生成相交链表, 注释掉之一行则为不相交
  135. while( pNode->next ) //找到链表1的尾结点
  136. pNode = pNode->next;
  137. pNode->next = phead2->next; //连接链表2的首结点
  138. struct node * pTail = check_loop( phead1 );//检查是否有环
  139. struct node * pFirstLoopNode = NULL;
  140. if( pTail )
  141. {
  142. cout <<"cross." <<endl;
  143. }
  144. else
  145. cout << "no cross." <<endl;
  146. }
  147. int _tmain(int argc, _TCHAR* argv[])
  148. {
  149. test();
  150. return 0;
  151. }

分别计算两链表的长度,为M,N。让指向长链表的指针先走,让两链表等长,

再两指针一起走,第一次相遇点即为相交点。

如果把相交链表变成一个环,则环的第一个结点即为相交点。


[cpp] view plaincopyprint?
  1. // LinkTable.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include "stdafx.h"
  4. #include <iostream>
  5. #include <string>
  6. using namespace std;
  7. //链表的结构体
  8. struct node
  9. {
  10. char val;
  11. node * next;
  12. };
  13. //建立链表
  14. struct node * create( string & str_link )
  15. {
  16. int len = str_link.length();
  17. struct node * phead =new node(); //带有表头的链表,表头中不存储任何元素
  18. struct node * preNode = phead;
  19. for( int i=0; i<len; i++ )
  20. {
  21. struct node * pNode =new node();
  22. pNode->val = str_link[i];
  23. pNode->next = NULL;
  24. preNode->next = pNode;
  25. preNode = pNode;
  26. }
  27. return phead;
  28. }
  29. //输出链表
  30. void out_link( struct node * phead )
  31. {
  32. if( phead == NULL )
  33. return;
  34. struct node * pNode = phead->next;
  35. while( pNode )
  36. {
  37. cout <<pNode->val;
  38. pNode = pNode->next;
  39. }
  40. cout << endl;
  41. }
  42. //找到第index个元素
  43. struct node * find_node(struct node* phead,int index )
  44. {
  45. if(!phead) return NULL;
  46. struct node * pNode = phead;
  47. while( index--)
  48. {
  49. pNode = pNode->next;
  50. if( !pNode )
  51. return NULL;
  52. }
  53. return pNode;
  54. }
  55. //检查链表有无环
  56. //有,则返回快慢指针共同指向的点
  57. //无,则返回空指针
  58. struct node * check_loop(struct node * phead )
  59. {
  60. if(!phead)
  61. return NULL;
  62. struct node * pFast = phead;
  63. struct node * pSlow = phead;
  64. int step = 1;
  65. while( pFast )
  66. {
  67. pFast = pFast->next;
  68. if( step++%2==0 )
  69. {
  70. pSlow = pSlow->next;
  71. if( pSlow == pFast )
  72. return pSlow;
  73. }
  74. }
  75. return NULL;
  76. }
  77. //求两个节点的距离,即中间有多少个连线
  78. //返回-1为出错,如果是同一节点,则返回0
  79. int find_length( struct node* pNode1,struct node* pNode2 )
  80. {
  81. if(!pNode1||!pNode2) return -1;
  82. int len=0;
  83. while( pNode1 )
  84. {
  85. if( pNode1 == pNode2 )
  86. return len;
  87. pNode1 = pNode1->next;
  88. len++;
  89. }
  90. return -1;
  91. }
  92. //找环的起始点,pTail为快慢指针共同指向的节点
  93. struct node * loop_first_node(struct node * phead, struct node * pTail )
  94. {
  95. if( !phead || !pTail ) return NULL;
  96. struct node * pNode1 = pTail->next;
  97. struct node * pNode2 = phead->next;
  98. int M = find_length( pNode1, pTail );
  99. int N = find_length( pNode2, pTail );
  100. if( M > N )
  101. {
  102. int step = M-N;
  103. while(step--)
  104. pNode1 = pNode1->next;
  105. }
  106. if( N > M )
  107. {
  108. int step = N-M;
  109. while(step--)
  110. pNode2 = pNode2->next;
  111. }
  112. while(pNode1&&pNode2)
  113. {
  114. if(pNode1 == pNode2 )
  115. return pNode1;
  116. pNode1 = pNode1->next;
  117. pNode2 = pNode2->next;
  118. }
  119. return NULL;
  120. }
  121. void test()
  122. {
  123. string str;
  124. cout << "Input the first link:"<<endl;
  125. cin >> str;
  126. struct node *phead1 = create( str );
  127. int index;
  128. cout << "Input the index of cross node: " <<endl;
  129. cin >> index;
  130. struct node * pNode1 = find_node( phead1, index );
  131. cout << "Input the second link:"<<endl;
  132. cin >> str;
  133. struct node *phead2 = create( str );
  134. struct node * pNode = phead2;
  135. while( pNode->next )
  136. pNode = pNode->next;
  137. pNode->next = pNode1; //生成相交链表, 注释掉这一行则为不相交
  138. while( pNode->next ) //找到链表1的尾结点
  139. pNode = pNode->next;
  140. pNode->next = phead2->next; //连接链表2的首结点
  141. struct node * pTail = check_loop( phead1 );//检查是否有环
  142. struct node * pFirstLoopNode = NULL;
  143. if( pTail )
  144. {
  145. cout <<"cross." <<endl;
  146. pFirstLoopNode = loop_first_node(phead1, pTail);
  147. cout <<"The cross node is: "<< pFirstLoopNode->val << endl;
  148. pNode->next = NULL; //还原,把环拆开
  149. }
  150. else
  151. cout << "no cross." <<endl;
  152. }
  153. int _tmain(int argc, _TCHAR* argv[])
  154. {
  155. test();
  156. return 0;
  157. }


 

例如:9->9->9->NULL

+ 1->NULL

1->0->0->0->NULL


思路:

使用递归,能够实现从前往后计算。


[cpp] view plaincopyprint?
  1. // LinkTable.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include "stdafx.h"
  4. #include <iostream>
  5. #include <string>
  6. using namespace std;
  7. //链表的结构体
  8. struct node
  9. {
  10. char val;
  11. node * next;
  12. };
  13. //建立链表
  14. struct node * create( string & str_link )
  15. {
  16. int len = str_link.length();
  17. struct node * phead =new node(); //带有表头的链表,表头中不存储任何元素
  18. struct node * preNode = phead;
  19. for( int i=0; i<len; i++ )
  20. {
  21. struct node * pNode =new node();
  22. pNode->val = str_link[i];
  23. pNode->next = NULL;
  24. preNode->next = pNode;
  25. preNode = pNode;
  26. }
  27. return phead;
  28. }
  29. //输出链表
  30. void out_link( struct node * phead )
  31. {
  32. if( phead == NULL )
  33. return;
  34. struct node * pNode = phead->next;
  35. while( pNode )
  36. {
  37. cout <<pNode->val;
  38. pNode = pNode->next;
  39. }
  40. cout << endl;
  41. }
  42. //求无表头链表的长度
  43. //返回-1为链表不存在
  44. int link_length( struct node* pNode )
  45. {
  46. if(!pNode) return -1;
  47. int len=0;
  48. while( pNode )
  49. {
  50. pNode = pNode->next;
  51. len++;
  52. }
  53. return len;
  54. }
  55. //大数相加递归算法
  56. //pNode1, pNode2为两个中间运算结点,但不是头结点
  57. struct node * add( struct node * pNode1,struct node * pNode2, int & carry )
  58. {
  59. if( !pNode1 ) return pNode2;
  60. if( !pNode2 ) return pNode1;
[cpp] view plaincopyprint?
  1. <SPAN style="WHITE-SPACE: pre"> </SPAN>//为了参数简洁,这里增大了计算量,可以将链表长度作为参数传进来
  2. int len1 = link_length( pNode1 );
  3. int len2 = link_length( pNode2 );
  4. if( len1 == len2 )
  5. {
  6. if( len1==1 ) //递归终止条件
  7. {
  8. struct node * pNode = new node();
  9. int sum = (pNode1->val -'0' ) + ( pNode2->val -'0');
  10. carry = sum/10;
  11. pNode->val = sum%10 + '0';
  12. pNode->next = NULL;
  13. return pNode;
  14. }
  15. else
  16. {
  17. int carry_cur=0;
  18. struct node * pNode = new node();
  19. struct node * pNext = add( pNode1->next, pNode2->next, carry_cur );
  20. int sum = (pNode1->val - '0' ) + ( pNode2->val -'0') + carry_cur;
  21. carry = sum/10;
  22. pNode->val = sum%10 + '0';
  23. pNode->next = pNext;
  24. return pNode;
  25. }
  26. }
  27. if( len1>len2 )
  28. {
  29. int carry_cur=0;
  30. struct node * pNode =new node();
  31. struct node * pNext = add( pNode1->next, pNode2, carry_cur );
  32. int sum = (pNode1->val -'0' ) + carry_cur;
  33. carry = sum/10;
  34. pNode->val = sum%10 + '0';
  35. pNode->next = pNext;
  36. return pNode;
  37. }
  38. if( len1<len2 )
  39. {
  40. int carry_cur=0;
  41. struct node * pNode =new node();
  42. struct node * pNext = add( pNode1, pNode2->next, carry_cur );
  43. int sum = (pNode2->val -'0' ) + carry_cur;
  44. carry = sum/10;
  45. pNode->val = sum%10 + '0';
  46. pNode->next = pNext;
  47. return pNode;
  48. }
  49. return NULL;
  50. }
  51. struct node * add(struct node * phead1, struct node * phead2 )
  52. {
  53. if( !phead1 || !phead1->next )return phead2;
  54. if( !phead2 || !phead2->next )return phead1;
  55. int carry = 0;
  56. struct node * pNode = add( phead1->next, phead2->next, carry );
  57. if( carry > 0 ) //有进位,则需要多一个结点
  58. {
  59. struct node * pCarry =new node();
  60. pCarry->val = '0' + carry;
  61. pCarry->next = pNode;
  62. pNode = pCarry;
  63. }
  64. struct node * phead =new node();
  65. phead->next = pNode;
  66. return phead;
  67. }
  68. void test()
  69. {
  70. string str;
  71. cout << "Input the first link:"<<endl;
  72. cin >> str;
  73. struct node *phead1 = create( str );
  74. cout << "Input the second link:"<<endl;
  75. cin >> str;
  76. struct node *phead2 = create( str );
  77. struct node * phead = add( phead1, phead2);
  78. cout<< "The result is:" <<endl;
  79. out_link( phead );
  80. }
  81. int _tmain(int argc, _TCHAR* argv[])
  82. {
  83. test();
  84. return 0;
  85. }

思路:

使用哈希表

从头扫描,将出现过的节点存入哈希表中。

如果元素已经在哈希表中出现过则删除,没有则存入。


注意:

删除时需要知道前一节点。

我使用的链表中存储的是char型变量,所以哈希表即为含有256个元素的数组。

如果存储的是其他数据类型,则可以使用stl中的hash_set容器。


[cpp] view plaincopyprint?
  1. // LinkTable.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include "stdafx.h"
  4. #include <iostream>
  5. #include <string>
  6. using namespace std;
  7. //链表的结构体
  8. struct node
  9. {
  10. char val;
  11. node * next;
  12. };
  13. //建立链表
  14. struct node * create( string & str_link )
  15. {
  16. int len = str_link.length();
  17. struct node * phead =new node(); //带有表头的链表,表头中不存储任何元素
  18. struct node * preNode = phead;
  19. for( int i=0; i<len; i++ )
  20. {
  21. struct node * pNode =new node();
  22. pNode->val = str_link[i];
  23. pNode->next = NULL;
  24. preNode->next = pNode;
  25. preNode = pNode;
  26. }
  27. return phead;
  28. }
  29. //输出链表
  30. void out_link( struct node * phead )
  31. {
  32. if( phead == NULL )
  33. return;
  34. struct node * pNode = phead->next;
  35. while( pNode )
  36. {
  37. cout <<pNode->val;
  38. pNode = pNode->next;
  39. }
  40. cout << endl;
  41. }
  42. //去掉重复元素
  43. void delete_repeat_element(struct node * phead )
  44. {
  45. if( !phead || !phead->next )return;
  46. int * hashTable = newint[256](); //加括号是为了将hashTable中所有元素初始化为0
  47. struct node * pNode = phead->next;
  48. struct node * pPreNode = phead;
  49. while( pNode )
  50. {
  51. if( hashTable[pNode->val] !=0 )//说明已经出现过,该结点要删除
  52. {
  53. pPreNode->next = pNode->next;
  54. delete pNode; //删除结点
  55. pNode = pPreNode->next;
  56. }
  57. else //没有出现过,则置出现标记
  58. {
  59. hashTable[pNode->val] = 1;
  60. pPreNode = pNode;
  61. pNode = pNode->next;
  62. }
  63. }
  64. delete [] hashTable; //释放资源
  65. }
  66. void test()
  67. {
  68. string str;
  69. cout << "Input the link table :"<<endl;
  70. cin >> str;
  71. struct node *phead = create( str );
  72. delete_repeat_element( phead );
  73. cout<< "The result is:" <<endl;
  74. out_link( phead );
  75. }
  76. int _tmain(int argc, _TCHAR* argv[])
  77. {
  78. test();
  79. return 0;
  80. }

思路1:

将链表中的数据存入数组中,使用数组进行排序,排好后再存入链表中。

当然这并不是这题所要考察的。但是在实际应用中却相当有价值。因为链表中的排序算法都比较慢,进行转存再排序也是一种很好的方法。


思路2:

排序算法有

1, 插入排序:简单插入排序,希尔排序

2, 交换排序:冒泡排序, 快速排序

3, 选择排序:简单选择排序,堆排序

4, 归并排序

5, 基数排序

简单的排序算法有插入,冒泡,选择;

中等的有合并排序,快速排序

复杂的有堆排序。


我实现了红色的三种排序方法。

使用链表进行排序比较繁琐,尤其是快排,需要拆分,

当然也可以多加一个指针指向要排序的队尾,这样就不用拆了。


[cpp] view plaincopyprint?
  1. // LinkTable.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include "stdafx.h"
  4. #include <iostream>
  5. #include <string>
  6. using namespace std;
  7. //链表的结构体
  8. struct node
  9. {
  10. char val;
  11. node * next;
  12. };
  13. //建立链表
  14. struct node * create( string & str_link )
  15. {
  16. int len = str_link.length();
  17. struct node * phead =new node(); //带有表头的链表,表头中不存储任何元素
  18. struct node * preNode = phead;
  19. for( int i=0; i<len; i++ )
  20. {
  21. struct node * pNode =new node();
  22. pNode->val = str_link[i];
  23. pNode->next = NULL;
  24. preNode->next = pNode;
  25. preNode = pNode;
  26. }
  27. return phead;
  28. }
  29. //输出链表
  30. void out_link( struct node * phead )
  31. {
  32. if( phead == NULL )
  33. return;
  34. struct node * pNode = phead->next;
  35. while( pNode )
  36. {
  37. cout <<pNode->val;
  38. pNode = pNode->next;
  39. }
  40. cout << endl;
  41. }
  42. //找到第index个元素
  43. struct node * find_node(struct node* phead,int index )
  44. {
  45. if(!phead) return NULL;
  46. struct node * pNode = phead;
  47. while( index--)
  48. {
  49. pNode = pNode->next;
  50. if( !pNode )
  51. return NULL;
  52. }
  53. return pNode;
  54. }
  55. //检查链表有无环
  56. //有,则返回快慢指针共同指向的点
  57. //无,则返回空指针
  58. struct node * check_loop(struct node * phead )
  59. {
  60. if(!phead)
  61. return NULL;
  62. struct node * pFast = phead;
  63. struct node * pSlow = phead;
  64. int step = 1;
  65. while( pFast )
  66. {
  67. pFast = pFast->next;
  68. if( step++%2==0 )
  69. {
  70. pSlow = pSlow->next;
  71. if( pSlow == pFast )
  72. return pSlow;
  73. }
  74. }
  75. return NULL;
  76. }
  77. //去掉重复元素
  78. void delete_repeat_element( struct node * phead )
  79. {
  80. if( !phead || !phead->next ) return;
  81. int * hashTable =new int[256]();//加括号是为了将hashTable中所有元素初始化为0
  82. struct node * pNode = phead->next;
  83. struct node * pPreNode = phead;
  84. while( pNode )
  85. {
  86. if( hashTable[pNode->val] !=0 )//说明已经出现过,该结点要删除
  87. {
  88. pPreNode->next = pNode->next;
  89. delete pNode; //删除结点
  90. pNode = pPreNode->next;
  91. }
  92. else //没有出现过,则置出现标记
  93. {
  94. hashTable[pNode->val] = 1;
  95. pPreNode = pNode;
  96. pNode = pNode->next;
  97. }
  98. }
  99. delete [] hashTable;//释放资源
  100. }
  101. //插入排序
  102. void insert_sort(struct node* phead)
  103. {
  104. if( !phead || !phead->next)return;
  105. struct node *pCur = phead->next->next;//当前处理的结点
  106. struct node *pTail = phead->next;//已排好序队列的尾部结点
  107. while( pCur )
  108. {
  109. struct node *pNode = phead->next;//已排好序队列中与当前结点相比较的结点
  110. struct node *pPre = phead; //...............前一结点
  111. while( pNode != pCur )
  112. {
  113. if(pNode->val > pCur->val)
  114. break;
  115. pNode = pNode->next;
  116. pPre = pPre->next;
  117. }
  118. if( pNode == pCur ) //说明已排好序队列中没有比当前元素大的元素
  119. {
  120. pCur = pCur->next;
  121. pTail = pTail->next;
  122. }
  123. else //将pCur结点插入到pNode之前,即pPre之后
  124. {
  125. pTail->next = pCur->next;
  126. pPre->next = pCur;
  127. pCur->next = pNode;
  128. pCur = pTail->next;
  129. }
  130. }
  131. }
  132. //归并排序
  133. //pNode 为待排序链表的第一个元素
  134. //找中间结点
  135. struct node * find_mid_node(struct node * pNode )
  136. {
  137. if( !pNode ) return NULL;
  138. struct node * pFast = pNode;
  139. struct node * pSlow = pNode;
  140. int step=1;
  141. while( pFast->next )
  142. {
  143. pFast = pFast->next;
  144. if( step++%2==0 )
  145. pSlow = pSlow->next;
  146. }
  147. return pSlow;
  148. }
  149. //合并之后,pNode1为表头
  150. void merge(struct node* &pNode1,struct node* pNode2)
  151. {
  152. if( !pNode1 ) //特殊情况
  153. {
  154. pNode1 = pNode2;
  155. return;
  156. }
  157. if( !pNode2 ) return;
  158. struct node *pNode = NULL;
  159. struct node *phead = NULL;
  160. if( pNode1->val < pNode2->val )//找到表头
  161. {
  162. phead = pNode1;
  163. pNode1 = pNode1->next;
  164. }
  165. else
  166. {
  167. phead = pNode2;
  168. pNode2 = pNode2->next;
  169. }
  170. pNode = phead;
  171. while( pNode1 && pNode2 )
  172. {
  173. if( pNode1->val < pNode2->val)
  174. {
  175. pNode->next = pNode1;
  176. pNode1 = pNode1->next;
  177. }
  178. else
  179. {
  180. pNode->next = pNode2;
  181. pNode2= pNode2->next;
  182. }
  183. pNode = pNode->next;
  184. }
  185. if( !pNode1 )
  186. pNode->next = pNode2;
  187. else
  188. pNode->next = pNode1;
  189. pNode1 = phead;
  190. }
  191. //注意,这里的pNode是需要变的,所以用了引用,可能不太好理解
  192. //如果让返回值指向排行序的表头可能会好一些
  193. void merge_sort( struct node * &pNode )
  194. {
  195. if( !pNode || !pNode->next ) return; //递归终止条件,无结点或者只有一个结点
  196. struct node* pMid = find_mid_node( pNode );//分解成两半
  197. struct node* pNode2 = pMid->next;
  198. pMid->next = NULL;
  199. merge_sort( pNode );
  200. merge_sort( pNode2 );
  201. merge( pNode, pNode2);
  202. }
  203. //快速排序
  204. //划分函数
  205. //输入:链表头, 输出:新的链表头,选中的结点
  206. struct node * patition(struct node * pNode, struct node * &pSelect )
  207. {
  208. if( !pNode ) return NULL;
  209. struct node* phead = NULL;
  210. pSelect = pNode; //选中的元素,划分的依据结点,选最后一个元素
  211. while( pSelect->next )
  212. pSelect = pSelect->next;
  213. struct node *pScan = pNode;
  214. struct node *pPre = NULL; //指向pScan前一个结点
  215. int flag = 0;
  216. while( pScan != pSelect )
  217. {
  218. if( pScan->val >pSelect->val )//比选中元素大的要掉到选中元素之后
  219. {
  220. if( !pPre ) //如果是第一个
  221. {
  222. struct node *temp = pScan;
  223. pScan = pScan->next;
  224. temp->next = pSelect->next;
  225. pSelect->next = temp;
  226. }
  227. else //如果不是第一个
  228. {
  229. pPre->next = pScan->next;
  230. pScan->next = pSelect->next;
  231. pSelect->next = pScan;
  232. pScan = pPre->next;
  233. }
  234. }
  235. else
  236. {
  237. if( flag ==0 )
  238. {
  239. phead = pScan; //第一个小于选中的元素为表头
  240. flag = 1;
  241. }
  242. pPre = pScan;
  243. pScan = pScan->next;
  244. }
  245. }
  246. if( flag == 0 ) // 所有元素都比选中的大,即选中的为表头
  247. return pSelect;
  248. else
  249. return phead;
  250. }
  251. struct node * QuickSort( struct node * pNode )
  252. {
  253. if( !pNode || !pNode->next ) return pNode;
  254. struct node * pSelect=NULL;
  255. pNode = patition( pNode, pSelect );
  256. if( pSelect == pNode ) //划分后的结点为第一个结点
  257. {
  258. pSelect->next = QuickSort(pSelect->next);
  259. return pSelect;
  260. }
  261. else //分两个部分,pSelect前面的和后面的
  262. {
  263. struct node * pFirstTail = pNode;
  264. while( pFirstTail->next != pSelect )
  265. pFirstTail = pFirstTail->next;
  266. pFirstTail->next = NULL; //断开
  267. struct node * phead1 = QuickSort( pNode );//解决前一部分
  268. pFirstTail = phead1;
  269. while( pFirstTail->next )
  270. pFirstTail = pFirstTail->next;
  271. pFirstTail->next = pSelect; //连上
  272. pSelect->next = QuickSort( pSelect->next ); //解决后一部分
  273. return phead1;
  274. }
  275. }
  276. void test()
  277. {
  278. string str;
  279. cout << "Input the link table :"<<endl;
  280. cin >> str;
  281. struct node *phead = create( str );
  282. //insert_sort( phead ); //选中即为插入排序
  283. //merge_sort( phead->next ); //选中即为归并排序
  284. phead->next = QuickSort( phead->next); //选中即为快速排序
  285. cout<< "The result of Sort is:" <<endl;
  286. out_link( phead );
  287. }
  288. int _tmain(int argc, _TCHAR* argv[])
  289. {
  290. test();
  291. return 0;
  292. }



 

原创粉丝点击