当前位置:   article > 正文

数据结构-单链表(带头结点与不带头结点表示)

数据结构-单链表(带头结点与不带头结点表示)

概念


一、单链表是什么?

单链表是线性表的链式存取结构;是用一组地址任意的存储单元存放线性表中的数据元素。链表中的数据是以结点来表示的;

  • 结点结构:

  • 申请新的结点:s = new Node<int> ;

二、带头结点与不带头结点的单链表,在进行操作时的区别
  • 当对单链表的表首元素进行删除或插入操作时,要进行区别处理,无头结点的单链表进行头指针的更新。(对表头特殊处理)

  • 带头结点的单链表,无论单链表是否为空链表,头指针都指向头结点。不带头结点的单链表,当单链表为非空链表时,头指针指向链表第一个结点(head),当单链表为空链表时,头指针指向空(NULL)。


创建单链表

1.结点结构
  1. //创建结点
  2. template<classT>
  3. struct Node {
  4. T data;
  5. Node<T> *next;
  6. };
  1. LinkList模板类
  1. template<classT>
  2. class LinkList
  3. {
  4. Node<T> *first,*rear,*p,*s,*q; //一般情况头指针用*first
  5. // 带结点单链表中头结点用*head
  6. public:
  7. LinkList();
  8. LinkList(Ta[], intn);
  9. ~LinkList();
  10. int Length(); //求链表长度
  11. T Get(intpos); //按值查找
  12. void Insert(inti, Titem);
  13. void HeadInsert(Ta[], intn); //头插法
  14. void TailInsert(Ta[], intn); //尾插法
  15. void Insert(inti, Titem);
  16. void Detele(inti);
  17. int CountX(Tdata);
  18. void PrintLinkList(); //遍历单链表
  19. };

3. 构造函数
  • 图解

  • 带头结点
  1. //头指针指向的结点为该单链表的头结点
  2. template<classT>
  3. LinkList<T>::LinkList() //无参构造函数
  4. {
  5. head=new Node<T>; //声明一个头结点
  6. head->next=NULL; //头结点指向的首结点为空
  7. }
  8. template<classT>
  9. LinkList<T>::LinkList(Ta[], intn) //有参构造函数
  10. {
  11. Node<T>*s;
  12. Node<T>*head=new Node<T>; //创建头结点
  13. rear=head;
  14. for (inti=0; i<n; i++) {
  15. s=new Node<T>; //申请新结点
  16. s->data=a[i];
  17. rear->next=s;
  18. rear=s;
  19. }
  20. rear->next=NULL;
  21. }
  • 不带头结点
  1. //头指针指向的结点为该单链表的首结点
  2. template<classT> //无参构造函数
  3. LinkList<T>::LinkList()
  4. {
  5. first=new Node<T>; //头指针指向新节点
  6. first=NULL; //首结点数据为空
  7. }
  8. template<classT>
  9. LinkList<T>::LinkList(Ta[], intn) {
  10. Node<T>*s=new Node<T>; //建立新结点指针
  11. first=s; //头指针指向新结点 s
  12. Node<T>*rear=first; // rear指向首结点
  13. for (inti=0; i<n; i++) {
  14. s=newNode<T>; //新结点
  15. s->data=a[i];
  16. rear->next=s; //插入 s
  17. rear=s; // s为尾结点
  18. }
  19. rear->next=NULL; //尾结点next设为空
  20. }
4.析构函数
  1. template<classT>
  2. LinkList<T>::~LinkList() {
  3. Node<T>*rear=first; // 头指针赋值给尾结点
  4. while (rear) { //当结点指针不为零
  5. Node<T>*q=rear; // Node<T> *q = first;
  6. rear=rear->next; //尾指针rear 递推 , 最后rear=NULL
  7. deleteq;
  8. }
  9. first=NULL; //当结点指针为零 ,则为空
  10. }
5. 头插法建表

[] 将待插入结点插在头结点的后面

  • 带头结点
  1. template<classT>
  2. LinkList<T>::~LinkList() {
  3. Node<T>*rear=first; // 头指针赋值给尾结点
  4. while (rear) { //当结点指针不为零
  5. Node<T>*q=rear; // Node<T> *q = first;
  6. rear=rear->next; //尾指针rear 递推 , 最后rear=NULL
  7. deleteq;
  8. }
  9. first=NULL; //当结点指针为零 ,则为空
  10. }
  1. template<classT>
  2. void LinkList<T>::HeadInsert(Ta[], intn) {
  3. head=new Node<T>;
  4. head->next=NULL;
  5. for (inti=0; i<n; i++) {
  6. //生成新结点
  7. //链接在头结点和首结点之间
  8. s=newNode<T>;
  9. s->data=a[i];
  10. s->next=head->next;
  11. head->next=s;
  12. }
  13. }
  • 不带头结点
  1. //插入到第一个位置
  2. s->next=first;
  3. first=s;
  4. //插入到其他位置
  5. //rear = 插入之前的结点;
  6. s->next=rear->next;
  7. rear->next=s;
  1. template<classT>
  2. void LinkList<T>::HeadInsert(Ta[], intn) {
  3. for (inti=0; i<n; i++) {
  4. rear=first; // rear指针指向原首元结点地址first
  5. s=new Node<T>; //新结点 s
  6. s->data=a[i];
  7. if (i==0) {
  8. s->next=NULL; // 头插法数组第一个元素最终为表尾元素
  9. }
  10. else {
  11. s->next=rear; //在尾部加上新结点 s
  12. }
  13. first=s; // 头指针指向 s, s为首元结点 (更新头指针)
  14. }
  15. }
6. 尾插法建表

[将待插入结点插在终端结点的后面]

  • 带头结点
  1. template<classT>
  2. void LinkList<T>::TailInsert(Ta[], intn) {
  3. rear=head;
  4. for (inti=0; i<n; i++) {
  5. //生成新结点
  6. //链接在尾结点后面
  7. //尾结点后移
  8. s=new Node<T>;
  9. s->data=a[i];
  10. rear->next=s;
  11. rear=s;
  12. }
  13. rear->next=NULL;
  14. }
  • 不带头结点
  1. template<classT>
  2. void LinkList<T>::TailInsert(Ta[], intn)
  3. {
  4. rear=first; // rear指针指向原首元结点地址first
  5. for (inti=0; i<n; i++) {
  6. s=new Node<T>; //新结点 s
  7. s->data=a[i];
  8. s->next=NULL;
  9. if(i==0){
  10. first=s ; // 如果当前是第一个元素则将头指针指向当前节点
  11. }
  12. else {
  13. rear->next=s; //在尾部加上新结点 s
  14. rear=s; // s 变为尾结点
  15. }
  16. rear=s;
  17. rear->next=NULL; //尾结点 next为空
  18. }
  19. }

7.插入(后插)

[] 在第 i个位置插入元素 item

  • 带头结点
  1. template<classT>
  2. void LinkList<T>::Insert(inti, Titem) {
  3. p=head;
  4. int j=0;
  5. while (p&&j<i-1) {
  6. p=p->next;
  7. j++;
  8. }
  9. if (!p||i==0) {
  10. cerr<<"插入位置非法。";
  11. exit(1);
  12. }
  13. s=newNode<T>;
  14. s->data=item;
  15. s->next=p->next;
  16. p->next=s;
  17. }
  • 不带头结点
  1. template<classT>
  2. void LinkList<T>::Insert(inti, Titem) {
  3. Node<T>*p=first; // p指向首元结点
  4. Node<T>*s=new Node<T>;
  5. if(i==1){ //插入第1个结点的操作
  6. s->data=item;
  7. s->next=first; //将 s放到first(首元素)前面
  8. first=s; //头指针指向 s (更改头指针)
  9. }
  10. else {
  11. intj=1; //第二个元素开始
  12. while (p&&j<i-1) { //找到插入元素位置的前驱结点
  13. p=p->next;
  14. j++;
  15. }
  16. if (!p||i==0) {
  17. cerr<<"插入位置非法。";
  18. exit(1);
  19. }
  20. s->data=item;
  21. s->next=p->next; // s->next为第 i个元素地址
  22. p->next=s; // 第 i-1元素 next为新元素 s
  23. }
  24. }

8.求链表长度
  1. //带头结点
  2. template<classT>
  3. int LinkList<T>::Length() {
  4. p=head->next; //不带头结点:p = first;
  5. int num=0;
  6. while (p) {
  7. p=p->next;
  8. num++;
  9. }
  10. return num;
  11. }

9.查找
  • 按位查找

  1. //根据位置获取元素
  2. template <class T>
  3. T LinkList<T>::Get(int pos)
  4. {
  5. p = head->next;
  6. int j=1;
  7. while(p&&j<pos) {
  8. p=p->next;
  9. j++;
  10. }
  11. if(!p||j>pos) {
  12. cerr<<"查找位置非法"<<endl;
  13. exit(1);
  14. }
  15. else {
  16. return p->data;
  17. }
  18. }
  • 按值查找

  1. //寻找某元素的位置
  2. template <class T>
  3. int LinkList<T>::Locate(T item) {
  4. p = head->next;
  5. int j=1;
  6. while(p&&p->data!=item) {
  7. p=p->next;
  8. j++;
  9. }
  10. if(p) {
  11. return j;
  12. }
  13. else {
  14. return 0;
  15. }
  16. }

10.遍历单链表
  1. //带头结点
  2. template<classT>
  3. void LinkList<T>::PrintLinkList() {
  4. p=head->next; //不带头结点 p = first;
  5. if(!p){ //空链表
  6. cout<<"The LinkList is empty !"<<endl;
  7. }
  8. else{
  9. cout<<"LinkList: " ;
  10. while (p) { // p不为NULL时依次输出
  11. cout<<p->data ;
  12. if(p->next!=NULL) { cout<<","; }
  13. p=p->next;
  14. }
  15. }
  16. cout<<endl;
  17. }


完整代码及实例

LinkList.h
带头结点
  1. #include<iostream>
  2. using namespace std;
  3. template<classT>
  4. structNode {
  5. Tdata;
  6. Node<T>*next;
  7. };
  8. template<classT>
  9. class LinkList
  10. {
  11. Node<T> *head,*rear,*q,*p,*s;
  12. public:
  13. LinkList();
  14. LinkList(Ta[], intn);
  15. ~LinkList();
  16. int Length();
  17. T Get(intpos);
  18. int CountX(Tdata);
  19. void PrintLinkList();
  20. void HeadInsert(Ta[], intn);
  21. void TailInsert(Ta[], intn);
  22. void Insert(inti, Titem);
  23. void Detele(inti);
  24. };
  25. template<classT>
  26. LinkList<T>::LinkList()
  27. {
  28. head=new Node<T>;
  29. head->next=NULL;
  30. }
  31. template<classT>
  32. LinkList<T>::LinkList(Ta[], intn) {
  33. Node<T>*s;
  34. head=new Node<T>;
  35. rear=head;
  36. for (inti=0; i<n; i++) {
  37. s=new Node<T>;
  38. s->data=a[i];
  39. rear->next=s;
  40. rear=s;
  41. }
  42. rear->next=NULL;
  43. }
  44. template<classT>
  45. LinkList<T>::~LinkList() {
  46. p=head;
  47. while (p) {
  48. q=p;
  49. p=p->next;
  50. deleteq;
  51. }
  52. head=NULL;
  53. }
  54. template<classT>
  55. int LinkList<T>::Length() {
  56. p=head->next;
  57. int num=0;
  58. while (p) {
  59. p=p->next;
  60. num++;
  61. }
  62. return num;
  63. }
  64. template<classT>
  65. T LinkList<T>::Get(intpos) {
  66. p=head->next;
  67. int j=1;
  68. while (p&&j<pos) {
  69. p=p->next;
  70. j++;
  71. }
  72. if (!p||j>pos)
  73. {
  74. cerr<<"查找位置非法。";
  75. exit(1);
  76. }
  77. else return p->data;
  78. }
  79. template<classT>
  80. int LinkList<T>::CountX(Tdata) {
  81. int count=0;
  82. p=head->next;
  83. intj=0;
  84. while(p)
  85. {
  86. if(p->data==data) {
  87. count++;
  88. }
  89. p=p->next;
  90. }
  91. return count;
  92. }
  93. template<classT>
  94. void LinkList<T>::Insert(inti, Titem) {
  95. p=head;
  96. intj=0;
  97. while (p&&j<i-1) {
  98. p=p->next;
  99. j++;
  100. }
  101. if (!p||i==0) {
  102. cerr<<"插入位置非法。";
  103. exit(1);
  104. }
  105. s=new Node<T>;
  106. s->data=item;
  107. s->next=p->next;
  108. p->next=s;
  109. }
  110. template<classT>
  111. voidLinkList<T>::HeadInsert(Ta[], intn) {
  112. head=new Node<T>;
  113. for (inti=0; i<n; i++) {
  114. s=new Node<T>;
  115. s->data=a[i];
  116. s->next=head->next;
  117. head->next=s;
  118. }
  119. }
  120. template<classT>
  121. void LinkList<T>::TailInsert(Ta[], intn) {
  122. rear=head;
  123. for (inti=0; i<n; i++) {
  124. s=new Node<T>;
  125. s->data=a[i];
  126. rear->next=s;
  127. rear=s;
  128. }
  129. rear->next=NULL;
  130. }
  131. template<classT>
  132. void LinkList<T>::Detele(inti) {
  133. p=head;
  134. intj=0;
  135. while (p&&j<i-1) {
  136. p=p->next;
  137. j++;
  138. }
  139. if (!p||!p->next||i==0) {
  140. cerr<<"删除位置非法。";
  141. exit(1);
  142. }
  143. else
  144. {
  145. q=p->next;
  146. //T x = q->data;
  147. cout<<q->data<<endl;
  148. p->next=q->next;
  149. delete q;
  150. }
  151. }
  152. template<classT>
  153. void LinkList<T>::PrintLinkList() {
  154. p=head->next;
  155. if(!p){
  156. cout<<"The LinkList is empty !"<<endl;
  157. }
  158. else{
  159. cout<<"LinkList: " ;
  160. while (p) {
  161. cout<<p->data ;
  162. if(p->next!=NULL) { cout<<","; }
  163. p=p->next;
  164. }
  165. }
  166. cout<<endl;
  167. }

不带头结点

  1. #include<iostream>
  2. using namespace std;
  3. template<classT>
  4. struct Node {
  5. T data;
  6. Node<T> *next;
  7. };
  8. template<classT>
  9. class LinkList
  10. {
  11. Node<T> *first,*rear,*p,*s,*q;
  12. public:
  13. LinkList();
  14. LinkList(Ta[], intn);
  15. ~LinkList();
  16. int Length();
  17. T Get(intpos);
  18. int CountX(Tdata);
  19. void PrintLinkList();
  20. void HeadInsert(Ta[], intn);
  21. void TailInsert(Ta[], intn);
  22. void Insert(inti, Titem);
  23. void Detele(inti);
  24. };
  25. template<classT> //无参构造函数
  26. LinkList<T>::LinkList()
  27. {
  28. first=new Node<T>; //头指针指向新节点
  29. first=NULL; //新节点数据为空
  30. }
  31. template<classT>
  32. LinkList<T>::LinkList(Ta[], intn) {
  33. Node<T> *s=new Node<T>; //建立新结点指针
  34. first=s; //头指针指向新结点 s
  35. Node<T> *rear = first; // 头指针赋值给尾结点
  36. for (inti=0; i<n; i++) {
  37. s = new Node<T>; //新结点
  38. s->data=a[i];
  39. rear->next = s; //插入 s
  40. rear = s; // s为尾结点
  41. }
  42. rear->next = NULL; //尾结点next设为空
  43. }
  44. template<classT>
  45. LinkList<T>::~LinkList() {
  46. Node<T> *rear = first; // 头指针赋值给尾结点
  47. while (rear) { //当结点指针不为零
  48. Node<T> *q = rear; // Node<T> *q = first;
  49. rear = rear->next; //尾指针rear 递推 , 最后rear=0
  50. delete q;
  51. }
  52. first=NULL; //当结点指针为零 ,则为空
  53. }
  54. template<classT>
  55. int LinkList<T>::Length() {
  56. Node<T>*p = first;
  57. int num=0;
  58. while (p) {
  59. p=p->next;
  60. num++;
  61. }
  62. return num;
  63. }
  64. template<classT>
  65. T LinkList<T>::Get(intpos) {
  66. Node<T>*p = first;
  67. int j = 1;
  68. while (p && j<pos) { //找到第 pos的元素
  69. p = p->next;
  70. j++;
  71. }
  72. if (!p||j>pos)
  73. {
  74. cerr<<"查找位置非法。";
  75. exit(1);
  76. }
  77. else return p->data; //返回
  78. }
  79. template<classT>
  80. int LinkList<T>::CountX(Tdata) {
  81. int count=0;
  82. Node<T>*p = first;
  83. intj = 0;
  84. while(p)
  85. {
  86. if(p->data==data) {
  87. count++;
  88. }
  89. p=p->next;
  90. }
  91. return count;
  92. }
  93. template<classT>
  94. void LinkList<T>::Insert(inti, Titem) {
  95. Node<T>*p = first; // p指向首元结点
  96. Node<T>*s = new Node<T>;
  97. if(i==1){ //插入第1个结点的操作
  98. s->data = item;
  99. s->next = first; //将 s放到first(首元素)前面
  100. first = s; //头指针指向 s (更改头指针)
  101. }
  102. else {
  103. int j=1; //第二个元素开始
  104. while (p && j<i-1) { //找到插入元素位置的前驱结点
  105. p = p->next;
  106. j++;
  107. }
  108. if (!p||i==0) {
  109. cerr<<"插入位置非法。";
  110. exit(1);
  111. }
  112. s->data = item;
  113. s->next = p->next; // s->next为第 i个元素地址
  114. p->next = s; // 第 i-1元素 next为新元素 s
  115. }
  116. }
  117. template<classT>
  118. void LinkList<T>::HeadInsert(Ta[], intn) {
  119. for (inti=0; i<n; i++) {
  120. Node<T> *rear = first; // rear指针指向原首元结点地址first
  121. Node<T>*s =new Node<T>; //新结点 s
  122. s->data=a[i];
  123. if (i==0) {
  124. s->next=NULL; // 头插法数组第一个元素最终为表尾元素
  125. }
  126. else {
  127. s->next=rear; //在尾部加上新结点 s
  128. }
  129. first=s; // 头指针指向 s, s为首元结点 (更新头指针)
  130. }
  131. }
  132. template<classT>
  133. void LinkList<T>::TailInsert(Ta[], intn)
  134. {
  135. Node<T>*rear=first; // p指针指向原首元结点地址first
  136. for (inti=0; i<n; i++) {
  137. Node<T>*s = newNode<T>; //新结点 s
  138. s->data = a[i];
  139. s->next = NULL;
  140. if(i==0){
  141. first = s ; // 如果当前是第一个元素则将头指针指向当前节点
  142. }
  143. else {
  144. rear->next = s; //在尾部加上新结点 s
  145. rear=s; // s 变为尾结点
  146. }
  147. rear=s;
  148. rear->next=NULL; //尾结点 next为空
  149. }
  150. }
  151. template<classT>
  152. void LinkList<T>::Detele(inti) {
  153. if(i==1) //删除第一个结点需要更换头指针
  154. {
  155. Node<T> *q = first; // q指向第一个元素头指针指向的首元结点地址
  156. T x = first->data; //存放准备删除的元素
  157. first = q->next; //头指针指向第二个元素的地址
  158. delete q;
  159. cout<<x<<endl;
  160. }
  161. else {
  162. Node<T> *p = first; // p先从指向首元素开始
  163. int j = 1; //第二个元素开始
  164. while (p && j<i-1) { // p指向将删除元素 q的前驱结点
  165. p = p->next;
  166. j++;
  167. }
  168. Node<T> *q = p->next; // q指向将删除结点
  169. T x = q->data;
  170. p->next = q->next; //将*q结点从链中"断开"
  171. delete q;
  172. cout<<x<<endl;
  173. }
  174. }
  175. template<classT>
  176. void LinkList<T>::PrintLinkList() {
  177. Node<T> *p = first;
  178. if(!p){ //空链表
  179. cout<<"The LinkList is empty !"<<endl;
  180. }
  181. else{
  182. cout<<"LinkList: " ;
  183. while (p) { // p不为NULL时依次输出
  184. cout<<p->data ;
  185. if(p->next!=NULL) { cout<<","; }
  186. p=p->next;
  187. }
  188. }
  189. cout<<endl;
  190. }

LinkList.cpp

  1. #include<iostream>
  2. #include "LinkList_1.h"
  3. using namespace std;
  4. int main(){
  5. intmyData[] = {4,8,8,2,9,1,7,6,4,3,2,9,11,7,9};
  6. cout<<" — — — — > Practice One < — — — — "<<endl;
  7. /*利用无参构造函数建立单链表(myLinkList1) ,并打印出该单链表讯息。
  8. 此时,单链表中应无数据,打印出无数据的讯息。
  9. 在主程序中,采用 for 循环依序将数组 myData 中的数据插入单链表(myLinkList1)中,并打印出该单链表讯息。
  10. int myData[15] = { 4,8,8,2,9,1,7,6,4,3,2,9,11,7,9 };
  11. */
  12. LinkList<int> myLinkList_1;
  13. myLinkList_1.PrintLinkList();
  14. int myLength=sizeof(myData)/sizeof(*myData);
  15. cout<<"The length of input data is :"<<myLength<<endl;
  16. for(inti=1;i<=myLength;i++){
  17. myLinkList_1.Insert(i,myData[i-1]);
  18. }
  19. myLinkList_1.PrintLinkList();
  20. ​ cout<<endl<<endl;
  21. LinkList<int>myLinkList_2(myData,myLength);
  22. cout<<" — — — — > Practice Two < — — — — "<<endl;
  23. /*利用有参构造函数建立单链表 ,并打印出该单链表讯息。
  24. int myData[15] = { 4,8,8,2,9,1,7,6,4,3,2,9,11,7,9 };
  25. 头插法: myLinkList2
  26. 尾插法: myLinkList3
  27. */
  28. cout<<"Inserting a node at the Beginning of a linked listed list ."<<endl;
  29. myLinkList_2.HeadInsert(myData,myLength);
  30. myLinkList_2.PrintLinkList();
  31. cout<<endl;
  32. cout<<"Inserting a node at the End of a linked listed list ."<<endl;
  33. myLinkList_2.TailInsert(myData,myLength);
  34. myLinkList_2.PrintLinkList();
  35. cout<<endl<<endl;
  36. cout<<" — — — — > Practice Three < — — — — "<<endl;
  37. /*
  38. 删除单链表中的元素
  39. 试写一个函数删除单链表中的结点,并返回被删除结点的内容。
  40. 针对 myLinkList1 中的内容进行删除。
  41. 删除第 1 个元素,并打印出删除元素的内容。
  42. 删除第 5 个元素,并打印出删除元素的内容。
  43. */
  44. cout<<"The data of the detele node is : " ;
  45. myLinkList_1.Detele(1);
  46. myLinkList_1.PrintLinkList();
  47. cout<<endl;
  48. cout<<"The data of the detele node is : " ;
  49. myLinkList_1.Detele(5);
  50. myLinkList_1.PrintLinkList();
  51. cout<<endl<<endl;
  52. cout<<" — — — — > Practice Four < — — — — "<<endl;
  53. /*试写一个函数計算单链表中所储存数据的个数,并返回计算的结果。
  54. 针对 myLinkList1 中的内容进行计算。
  55. 统计 9 的个数。
  56. */
  57. cout<<"The number of 9 "<<"is "<<myLinkList_1.CountX(9) <<endl;
  58. }

运行结果

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/515609
推荐阅读
相关标签
  

闽ICP备14008679号