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

概念


一、单链表是什么?

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

  • 结点结构:

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

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

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


创建单链表

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

3. 构造函数
  • 图解

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

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

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

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

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

7.插入(后插)

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

  • 带头结点
 template<classT>
 void LinkList<T>::Insert(inti, Titem) {
      p=head;
      int j=0;
      while (p&&j<i-1) {
           p=p->next;
           j++;
      }
      if (!p||i==0) {
           cerr<<"插入位置非法。";
           exit(1);
      }
     s=newNode<T>;
      s->data=item;
      s->next=p->next;
      p->next=s;
 }
  • 不带头结点
 template<classT>
 void LinkList<T>::Insert(inti, Titem) {
      Node<T>*p=first;   // p指向首元结点 
      Node<T>*s=new Node<T>;
      if(i==1){   //插入第1个结点的操作
           s->data=item;
          s->next=first;   //将 s放到first(首元素)前面 
          first=s;   //头指针指向 s (更改头指针) 
      }
     else {  
      intj=1;  //第二个元素开始 
      while (p&&j<i-1) {   //找到插入元素位置的前驱结点 
           p=p->next;
           j++;
      }
      if (!p||i==0) {
           cerr<<"插入位置非法。";
           exit(1);
         }
      s->data=item;
      s->next=p->next;   // s->next为第 i个元素地址
      p->next=s;    // 第 i-1元素 next为新元素 s 
     }
 }

8.求链表长度
//带头结点
template<classT>
int LinkList<T>::Length() {
      p=head->next;       //不带头结点:p = first;
      int num=0;
      while (p) {
           p=p->next;
           num++;
      }
      return num;
 }

9.查找
  • 按位查找

 //根据位置获取元素 
template <class T>
T LinkList<T>::Get(int pos)
 {
      p = head->next;
      int j=1;
      while(p&&j<pos) {
           p=p->next;
           j++;
      }
      if(!p||j>pos) {
           cerr<<"查找位置非法"<<endl; 
           exit(1);
      }
      else {
           return p->data; 
      } 
 }
  • 按值查找

 //寻找某元素的位置 
template <class T>
int LinkList<T>::Locate(T item) {
      p = head->next;
      int j=1;
      while(p&&p->data!=item) {
           p=p->next;
           j++;
       } 
       if(p) {
          return j;
       }
       else {
          return 0;
       }
 }

10.遍历单链表
//带头结点
template<classT>
void LinkList<T>::PrintLinkList() {
     p=head->next;    //不带头结点 p = first;
     if(!p){   //空链表 
          cout<<"The LinkList is empty !"<<endl;
     }
     else{
         cout<<"LinkList: " ;
     while (p) {   // p不为NULL时依次输出 
              cout<<p->data ;
              if(p->next!=NULL)    {  cout<<",";     }
             p=p->next;
        }
      }
     cout<<endl;
 }


完整代码及实例

LinkList.h
带头结点
 #include<iostream>
 using namespace std;
 ​
 template<classT>
 structNode {
      Tdata;
      Node<T>*next;
 }; 
template<classT>
class LinkList
 {
      Node<T> *head,*rear,*q,*p,*s;
 public:
      LinkList();
      LinkList(Ta[], intn);
      ~LinkList();
      int Length();
      T Get(intpos);
     int CountX(Tdata);
      void PrintLinkList();
      void HeadInsert(Ta[], intn);
      void TailInsert(Ta[], intn);
      void Insert(inti, Titem);
      void Detele(inti);
 ​
 };
 ​
template<classT>
LinkList<T>::LinkList()
 {
      head=new Node<T>;
      head->next=NULL; 
 }
 ​
template<classT>
LinkList<T>::LinkList(Ta[], intn) {
      Node<T>*s;
      head=new Node<T>;
      rear=head;
      for (inti=0; i<n; i++) {
           s=new Node<T>;
           s->data=a[i];
           rear->next=s;
           rear=s;
      }
      rear->next=NULL;
 }
 ​
template<classT>
LinkList<T>::~LinkList() {
      p=head;
      while (p) {
           q=p;
           p=p->next;
           deleteq;
      }
      head=NULL;
 }
 ​
template<classT>
int LinkList<T>::Length() {
      p=head->next;
      int num=0;
      while (p) {
           p=p->next;
           num++;
      }
      return num;
 }
 ​
template<classT>
T LinkList<T>::Get(intpos) {
      p=head->next;
      int j=1;
      while (p&&j<pos) {
           p=p->next;
           j++;
      }
      if (!p||j>pos)
      {
           cerr<<"查找位置非法。";
           exit(1);
      }
      else return p->data;
 }
 ​
template<classT>
int LinkList<T>::CountX(Tdata) {
      int count=0;
      p=head->next;
      intj=0;
      while(p)
     {
          if(p->data==data) {
             count++;
         }
           p=p->next;
     }
     return count;
 }
 ​
template<classT>
void LinkList<T>::Insert(inti, Titem) {
      p=head;
      intj=0;
      while (p&&j<i-1) {
           p=p->next;
           j++;
      }
      if (!p||i==0) {
           cerr<<"插入位置非法。";
           exit(1);
      }
     s=new Node<T>;
      s->data=item;
      s->next=p->next;
      p->next=s;
 }
 ​
template<classT>
voidLinkList<T>::HeadInsert(Ta[], intn) {
     head=new Node<T>;
      for (inti=0; i<n; i++) {
           s=new Node<T>;
           s->data=a[i];
           s->next=head->next;
           head->next=s;
      }
 }
 ​
template<classT>
void LinkList<T>::TailInsert(Ta[], intn) {
      rear=head;
      for (inti=0; i<n; i++) {
           s=new Node<T>;
           s->data=a[i];
           rear->next=s;
           rear=s;
      }
      rear->next=NULL;
 }
 ​
template<classT>
void LinkList<T>::Detele(inti) {
      p=head;
      intj=0;
      while (p&&j<i-1) {
           p=p->next;
           j++;
      }
      if (!p||!p->next||i==0) {
           cerr<<"删除位置非法。";
           exit(1);
      }
      else
      {
           q=p->next;
           //T x = q->data;
           cout<<q->data<<endl;
           p->next=q->next;
           delete q;
      }
 }
 ​
template<classT>
void LinkList<T>::PrintLinkList() {
      p=head->next;
      if(!p){
           cout<<"The LinkList is empty !"<<endl;
      }
      else{
          cout<<"LinkList: " ;
      while (p) {
               cout<<p->data ;
              if(p->next!=NULL)     {  cout<<",";     }
              p=p->next;
         }
 }
      cout<<endl;
 }

不带头结点

#include<iostream>
using namespace std;
 ​
template<classT>
struct Node {
      T data;
      Node<T> *next;
}; 
 ​
template<classT>
class LinkList
{
      Node<T> *first,*rear,*p,*s,*q;
 public:
      LinkList();
      LinkList(Ta[], intn);
      ~LinkList();
      int Length();
      T Get(intpos);
      int CountX(Tdata);
      void PrintLinkList();
      void HeadInsert(Ta[], intn);
      void TailInsert(Ta[], intn);
      void Insert(inti, Titem);
      void Detele(inti);
 ​
};
 ​
template<classT>  //无参构造函数 
LinkList<T>::LinkList()
{
     first=new Node<T>;  //头指针指向新节点 
     first=NULL;   //新节点数据为空 
}
 ​
template<classT>
LinkList<T>::LinkList(Ta[], intn) {
     Node<T> *s=new Node<T>;   //建立新结点指针 
     first=s;       //头指针指向新结点 s
     Node<T> *rear = first;  // 头指针赋值给尾结点 
     for (inti=0; i<n; i++) {
          s = new Node<T>;   //新结点 
          s->data=a[i];
          rear->next = s;    //插入 s 
          rear = s;      // s为尾结点 
      }
     rear->next = NULL;  //尾结点next设为空 
 }
 
template<classT>
LinkList<T>::~LinkList() {
     Node<T> *rear = first;  // 头指针赋值给尾结点 
     while (rear) {   //当结点指针不为零 
          Node<T> *q = rear;   // Node<T> *q = first;
          rear = rear->next;  //尾指针rear 递推 , 最后rear=0 
          delete q;
      }
     first=NULL;  //当结点指针为零 ,则为空 
 }
 ​
template<classT>
int LinkList<T>::Length() {
     Node<T>*p = first;
     int num=0;
      while (p) {
           p=p->next;
           num++;
      }
      return num;
 }
 ​
template<classT>
T LinkList<T>::Get(intpos) {
      Node<T>*p = first;
      int j = 1;
      while (p && j<pos) {  //找到第 pos的元素 
           p = p->next;
           j++;
      }
      if (!p||j>pos)  
      {
           cerr<<"查找位置非法。";
           exit(1);
      }
      else return p->data;  //返回 
 }
 ​
template<classT>
int LinkList<T>::CountX(Tdata) {
      int count=0;
      Node<T>*p = first;
      intj = 0;
      while(p)
     {
          if(p->data==data) {
             count++;
         }
          p=p->next;
     }
     return count;
 }
 ​
template<classT>
void LinkList<T>::Insert(inti, Titem) {
      Node<T>*p = first;   // p指向首元结点 
      Node<T>*s = new Node<T>;
      if(i==1){   //插入第1个结点的操作
           s->data = item;
          s->next = first;   //将 s放到first(首元素)前面 
          first = s;   //头指针指向 s (更改头指针) 
      }
     else {  
      int j=1;  //第二个元素开始 
      while (p && j<i-1) {   //找到插入元素位置的前驱结点 
           p = p->next;
           j++;
      }
      if (!p||i==0) {
           cerr<<"插入位置非法。";
           exit(1);
         }
      s->data = item;
      s->next = p->next;   // s->next为第 i个元素地址
      p->next = s;    // 第 i-1元素 next为新元素 s 
     }
 }
 ​
template<classT>
void LinkList<T>::HeadInsert(Ta[], intn) {
      for (inti=0; i<n; i++) {   
          Node<T> *rear = first;    // rear指针指向原首元结点地址first 
           Node<T>*s =new Node<T>; //新结点 s
           s->data=a[i];
           if (i==0) {   
                s->next=NULL;   // 头插法数组第一个元素最终为表尾元素
           }
          else {
              s->next=rear;   //在尾部加上新结点 s  
         }
         first=s;  // 头指针指向 s, s为首元结点 (更新头指针) 
     } 
 }
 ​
template<classT>
void LinkList<T>::TailInsert(Ta[], intn)
  { 
     Node<T>*rear=first;    // p指针指向原首元结点地址first 
     for (inti=0; i<n; i++) {   
           Node<T>*s = newNode<T>; //新结点 s
           s->data = a[i];
           s->next = NULL; 
           if(i==0){
                first = s ;   // 如果当前是第一个元素则将头指针指向当前节点
           }
          else {
              rear->next = s;   //在尾部加上新结点 s 
              rear=s;    // s 变为尾结点 
         }
         rear=s;
         rear->next=NULL;  //尾结点 next为空 
     }
 }
 ​
template<classT>
void LinkList<T>::Detele(inti) {
      if(i==1)  //删除第一个结点需要更换头指针   
      {
           Node<T> *q = first;    // q指向第一个元素头指针指向的首元结点地址
           T x = first->data;   //存放准备删除的元素 
           first = q->next;  //头指针指向第二个元素的地址
           delete q; 
           cout<<x<<endl;
      }
      else {
      Node<T> *p = first;  // p先从指向首元素开始 
          int j = 1;   //第二个元素开始 
          while (p && j<i-1) {  // p指向将删除元素 q的前驱结点
           p = p->next;
           j++;
           }  
          Node<T> *q = p->next;  // q指向将删除结点 
          T x = q->data;    
           p->next = q->next;   //将*q结点从链中"断开"
         delete q; 
         cout<<x<<endl;
     }
 }
     
template<classT>
void LinkList<T>::PrintLinkList() {
      Node<T> *p = first;    
      if(!p){   //空链表 
           cout<<"The LinkList is empty !"<<endl;
      }
      else{
          cout<<"LinkList: " ;
      while (p) {   // p不为NULL时依次输出 
               cout<<p->data ;
               if(p->next!=NULL)    {  cout<<",";     }
              p=p->next;
         }
 }
      cout<<endl;
 }

LinkList.cpp

#include<iostream>
#include "LinkList_1.h"
using namespace std;
int main(){
     intmyData[] = {4,8,8,2,9,1,7,6,4,3,2,9,11,7,9};
     cout<<" — — — — > Practice One < — — — — "<<endl;
/*利用无参构造函数建立单链表(myLinkList1) ,并打印出该单链表讯息。
 此时,单链表中应无数据,打印出无数据的讯息。
 在主程序中,采用 for 循环依序将数组 myData 中的数据插入单链表(myLinkList1)中,并打印出该单链表讯息。
 int myData[15] = { 4,8,8,2,9,1,7,6,4,3,2,9,11,7,9 }; 
*/
     LinkList<int> myLinkList_1; 
     myLinkList_1.PrintLinkList();   
     int myLength=sizeof(myData)/sizeof(*myData);
     cout<<"The length of input data is :"<<myLength<<endl;
     for(inti=1;i<=myLength;i++){
         myLinkList_1.Insert(i,myData[i-1]);
      }
     myLinkList_1.PrintLinkList();

 ​    cout<<endl<<endl;
     LinkList<int>myLinkList_2(myData,myLength);
     cout<<" — — — — > Practice Two < — — — — "<<endl;
/*利用有参构造函数建立单链表 ,并打印出该单链表讯息。
 int myData[15] = { 4,8,8,2,9,1,7,6,4,3,2,9,11,7,9 }; 
 头插法: myLinkList2
 尾插法: myLinkList3
*/
    cout<<"Inserting a node at the Beginning of a linked listed list ."<<endl;
           myLinkList_2.HeadInsert(myData,myLength);
           myLinkList_2.PrintLinkList();
    cout<<endl;
      
 ​
    cout<<"Inserting a node at the End of a linked listed list ."<<endl;
          myLinkList_2.TailInsert(myData,myLength);
          myLinkList_2.PrintLinkList();
 ​
    cout<<endl<<endl;
    cout<<" — — — — > Practice Three < — — — — "<<endl;
/*
 删除单链表中的元素
 试写一个函数删除单链表中的结点,并返回被删除结点的内容。
 针对 myLinkList1 中的内容进行删除。
 删除第 1 个元素,并打印出删除元素的内容。
 删除第 5 个元素,并打印出删除元素的内容。
*/
 ​
     cout<<"The data of the detele node is : " ;
     myLinkList_1.Detele(1);
     myLinkList_1.PrintLinkList();
     cout<<endl;
     cout<<"The data of the detele node is : " ;
     myLinkList_1.Detele(5);
     myLinkList_1.PrintLinkList();
 ​
    cout<<endl<<endl;
    cout<<" — — — — > Practice Four < — — — — "<<endl;
/*试写一个函数計算单链表中所储存数据的个数,并返回计算的结果。
 针对 myLinkList1 中的内容进行计算。
 统计 9 的个数。
*/
    cout<<"The number of 9 "<<"is "<<myLinkList_1.CountX(9) <<endl;   
 }

运行结果

  • 8
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值