1. 程式人生 > >C++連結串列操作總結和常見連結串列操作

C++連結串列操作總結和常見連結串列操作

一、連結串列的定義

連結串列是一種動態資料結構,他的特點是用一組任意的儲存單元(可以是連續的,也可以是不連續的)存放資料元素。連結串列中每一個元素成為“結點”,每一個結點都是由資料域和指標域組成的,每個結點中的指標域指向下一個結點。Head是“頭指標”,表示連結串列的開始,用來指向第一個結點,而最後一個指標的指標域為NULL(空地址),表示連結串列的結束。可以看出連結串列結構必須利用指標才能實現,即一個結點中必須包含一個指標變數,用來存放下一個結點的地址。實際上,連結串列中的每個結點可以用若干個資料和若干個指標。結點中只有一個指標的連結串列稱為單鏈表,這是最簡單的連結串列結構。再c++中實現一個單鏈表結構比較簡單。
例如,可定義單鏈表結構的最簡單形式如下:


struct Node
{
int Data;
Node*next;
};

這裡用到了結構體型別。其中,*next是指標域,用來指向該結點的下一個結點;Data是一個整形變數,用來存放結點中的資料。當然,Data可以是任何資料型別,包括結構體型別或類型別。在此基礎上,我們在定義一個連結串列類list,其中包含連結串列結點的插入,刪除,輸出等功能的成員函式。

下面簡單實現下結構體連結串列,程式碼如下:

#include <iostream>
using namespace std;

enum operation{create_List=1,print_List,insert_Node,delete_Node,delete_List,quit};//列舉型別,用於選單選擇結果
   
struct  node  //結點結構
{ int data ; 
  node * next; 
};  

operation  Menu(); //選單函式

node * CreateList( );  //建立連結串列函式宣告
void  PrintList( node *); //輸出連結串列中結點資訊函式宣告
node * InsertNode(node *,node *); //在連結串列中插入結點函式宣告
node * DeleteNode(node *,int); //在連結串列中刪除結點函式宣告 
node * deleteList(node *head); //刪除整個連結串列

void Create();  //對應操作選單--建立連結串列的操作
void Print( );  //對應操作選單--遍歷連結串列的操作
void Insert( ); //對應操作選單--插入連結串列結點的操作
void Delete( ); //對應操作選單--刪除連結串列結點的操作
void DeleteAll(); //對應操作選單--刪除整個連結串列的操作


int n=0; //全域性整型變數存放連結串列中結點個數
node * head=NULL ;  //全域性指標變數存放連結串列頭結點地址-頭指標


int main()
{   
  operation menu_choice;  //存放選單選擇項

  do   //迴圈現實直到使用者退出程式
  {
   menu_choice=Menu(); //選單顯示及使用者選擇
   switch(menu_choice) //使用者選擇功能匹配
   {
      case create_List: cout<<"1 建立連結串列"<<endl<<endl;
		                Create( );
					    break;
	  case  print_List: cout<<"2 遍歷連結串列"<<endl<<endl;
                       Print();
					   break;
      case  insert_Node: cout<<"3 插入連結串列結點"<<endl<<endl;
                       Insert();
					    break;
	  case  delete_Node: cout<<"4 刪除連結串列結點"<<endl<<endl;
                       Delete();
					    break;
      case  delete_List: cout<<"5 刪除整個連結串列"<<endl<<endl;
                       DeleteAll();
					    break;
	  case quit : 
	  default:   cout<<"退出連結串列操作,結束程式"<<endl;
		        return 0;

   }   
   
  }while(menu_choice!=quit);  

  return 0;
}

/*建立連結串列*/
node * CreateList( )  //建立連結串列函式
{ node * s, * p ; // s指向新結點,p指向連結串列中最後的結點 
  s = new node ;   //動態建立第一個新結點
  cout<<"請輸入一個整數值作為新結點的資料資訊,輸入0時建立連結串列結束"<<endl;
  cout<<"第"<<n+1<<"個結點"<<endl;
  cin >> s->data ;  //輸入新結點資料
  head = NULL ;   //頭指標初始值為NULL
  if( s->data==0)  //第一個結點資料就為0,建立一個空連結串列
  {
	  cout<<"您建立的空連結串列"<<endl;
      delete  s ;  //釋放資料為0的結點
  }
  else //建立非空連結串列
  {
	  while ( s->data != 0 )  //通過判斷新結點資料來進行迴圈
	  { if ( head == NULL )   head = s ; //頭指標賦值
		 else  p->next = s ;  //將新結點插入已有連結串列的最後
		p = s ; // p指向連結串列中最後的結點 
		n=n+1;//結點個數增1
		s = new node ; //動態建立一個新結點
		cout<<"請輸入一個整數值作為新結點的資料資訊,輸入0時建立連結串列結束"<<endl;
		cout<<"第"<<n+1<<"個結點"<<endl;
		cin >> s->data ; //輸入新結點資料
	  }
	  p -> next = NULL ; //設定連結串列尾部為空
	  delete  s ;  //釋放資料為0的結點
	  cout<<endl<<"連結串列建立完成...";
	  cout<<"建立的連結串列中共有"<<n<<"個節點"<<endl<<endl;
  }
  return ( head ) ; //返回頭指標 
}
  
/*遍歷連結串列*/
void  PrintList( node * head)  //輸出連結串列中結點資訊函式,連結串列遍歷
{    node *p=head;
     int i=1;
	 cout<<endl<<"遍歷連結串列..."<<endl;
    if (head!=NULL)  //如果連結串列非空,即連結串列中有結點
        do             //迴圈輸出接點資料,直到移動到連結串列尾,即最後一個結點
		{     cout<<"第"<<i++<<"個結點資料為:"<<p->data<<endl; 
               p=p->next;				
        }while(p!=NULL) ;
	else
	{
	  cout<<"連結串列是空連結串列!"<<endl;
	}
	 cout<<"連結串列中共有"<<n<<"個節點"<<endl;
}

/*插入結點*/  
node * InsertNode(node *head,node * s)  //插入結點的函式,head為連結串列頭指標,s指向要插入的新結點
{node *p,*q;                         
 p=head;   //使p指向連結串列中的第一個結點      
 if(head==NULL)      //原來的連結串列是空表
 { head=s;           //使head指向的新結點作為頭結點
   s->next=NULL;     
 }          
 else  //原來的連結串列不是空表
 {while((s->data>p->data) && (p->next!=NULL)) //用迴圈定位要插入的結點位置p,使s插入到p之前的位置
	{q=p;  //q記錄下當前的p,即q指向p的前一個結點
	 p=p->next;   //p後移一個結點
	}    
  if(s->data<=p->data)  //要插入的結點資料比最後一個結點資料小
  {	  if(head==p) //判斷是否插入連結串列中的第一個結點之前
	  { head=s;  //插到原來第一個結點之前      
		 s->next=p;
	 } 	  
	  else //插到q指向的結點之後,p指向的結點之前
	  { q->next=s;
		s->next=p;         
	  }  	  
  } 
  else   //要插入的結點資料比最後一個結點資料還大
  {  p->next=s;    // 插到連結串列最後的結點之後,作為連結串列的尾結點
     s->next=NULL;
  } 
 } 
   n=n+1;          //結點數加1 
   cout<<"成功完成一個新結點插入..."<<endl;
   return (head);
}
               
/*刪除結點*/
node *DeleteNode(node *head,int delData)   //刪除資料為delDate的結點的函式
{node *p,*q; 
 p=head;          //使p指向第一個結點
 if (head==NULL)     //是空表
 { cout<<"該連結串列是空連結串列,不能進行結點刪除!"<<endl; 
   return(head);
 }
 //先找到要刪除的結點                       
 while(delData!=p->data && p->next!=NULL) //p指向的不是所要找的結點且後面還有結點
 { q=p;  //q用來記錄p前一個結點
   p=p->next;
 }         //p後移一個結點
  if(delData==p->data)      //找到了要刪除的結點
  { if(p==head)  //如果要刪除的是頭結點
       head=p->next;   //若p指向的是首結點,把第二個結點地址賦予head
    else q->next=p->next;    //否則將下一結點地址賦給前一結點地址
    cout<<"成功刪除資料為"<<delData<<"的結點"<<endl;
    n=n-1;
 }
 else 
	 cout<<"要刪除的資料為"<<delData<<"的結點在連結串列中沒有找到"<<endl;     //找不到該結點
 return(head);
}

/*刪除整個連結串列*/
node * deleteList(node *head) //刪除整個連結串列
{ 
  node *p,*s;
  p=head;
  if(head==NULL)
	  cout<<"連結串列本身就為空連結串列";
  else
  {
	  while(p->next!=NULL)
	  {
	     s=p;
		 p=p->next;
		 delete s;
		 n--;
	  }  
	  delete p;
	  n--;
      head=NULL;
  }
  cout<<"整個連結串列刪除成功!"<<endl;
  return head;
}


/*選單函式*/
operation  Menu()
{  int choice;
   cout<<endl<<endl;
   cout<<"連結串列操作選單"<<endl;
   cout<<"1 建立連結串列"<<endl;
   cout<<"2 遍歷連結串列"<<endl;
   cout<<"3 插入連結串列結點"<<endl;
   cout<<"4 刪除連結串列結點"<<endl;
   cout<<"5 刪除整個連結串列"<<endl;
   cout<<"6 退出"<<endl;

   cout<<endl<<endl<<"請輸入功能序號";
   cin>>choice;
   return operation(choice);
}

/*對應操作選單--建立連結串列的操作*/
void Create()
{
    if(head==NULL) //如果連結串列中已有結點,不允許重新建立
	{
	  head=CreateList( ); 
	}
	else
	{
	  cout<<"已建立過連結串列,不允許再次建立"<<endl;
	  cout<<"如果想重新建立,先刪除原先連結串列"<<endl;	  
	}
}

/*對應操作選單--遍歷連結串列的操作*/
void Print( )
{
   PrintList(head);
}

/*對應操作選單--插入連結串列結點的操作*/
void Insert( )
{  
  char IsGo;  //是否繼續操作標誌
  IsGo='y';
  cout<<endl<<"開始進行結點插入操作"<<endl;  
  node *stu;   
  while(IsGo=='y'||IsGo=='Y')  
  {   stu=new node;    //建立要插入的新結點
      cout<<endl<<"輸入要插入的新結點資料:"; 
      cin>>stu->data;      //輸入要插入的新結點資料 	 
	  head=InsertNode(head,stu);    //呼叫插入函式,返回連結串列頭指標
	  cout<<"是否繼續插入新結點? (繼續插入請按y或Y,退出請按其它鍵)";
	  cin>>IsGo;    
  }
  cout<<endl<<"結點插入操作結束"<<endl;
}

/*對應操作選單--刪除連結串列結點的操作*/
void Delete( )
{
   char IsGo;  //是否繼續操作標誌
   int del_num;	//要刪除的結點的資料
   IsGo='y';
   cout<<endl<<"開始進行結點插入操作"<<endl;  
   while(IsGo=='y'||IsGo=='Y')
   {
	   cout<<endl<<"輸入要刪除的節點的資料:";  //輸入要插入的結點
	   cin>>del_num;  //輸入要刪除的結點的資料	
	   head=DeleteNode(head,del_num);    //刪除後連結串列的頭地址
       cout<<"是否繼續刪除結點? (繼續插入請按y或Y,退出請按其它鍵)";
	   cin>>IsGo;    
   }
     cout<<endl<<"結點刪除操作結束"<<endl;
}

/*對應操作選單--刪除整個連結串列的操作*/
void DeleteAll()
{
  head=deleteList(head);

}

單鏈表類的實現,程式碼如下:
/////////////////////////////////////////////////////////////////
//日期:2014-11-03
//作者:Davis
//功能:單鏈表的定義與操作實現
/////////////////////////////////////////////////////////////////
#pragma once
template<class T>
struct Node
{
    T data;     //資料域,存放表元素
    Node *next; //指標域。指向下一個結點
};

template<class T>
class linkList
{
private:

    Node<T> *Head; //連結串列頭指標

public:
    //建構函式、建立空連結串列
    linkList(void)
    {
      Head = new Node<T>;
      Head->next = NULL;
    }

    //解構函式、刪除空連結串列
    ~linkList(void)
    {
      Node<T> *p;
      while(Head)
      {
        p = Head;//從頭節點開始,依次釋放結點
        Head = Head->next;
        delete p;
      }
      Head = NULL;//頭結點指向空
    }

    //建立具有n個元素的線性連結串列
    void createList(int n)
    {                 //尾插法(正序)建立具有n個元素的線性表
      Node<T> *p,*s;  //設定工作指標,p指向尾結點
      p=Head;
      cout<<"請依次輸入"<<n<<"個元素值"<<endl;
      for(int i=1;i<=n;i++)
      {
        s = new Node<T>;   //新建元素結點
        cin>>s->data;      //輸入新建資料元素值
        s->next = p->next; //新結點鏈入表尾
        p->next = s;
        p = s;             //p是工作指標
      }
    }

    //在表中第i個位置插入元素
    void Insert(int i,T e)
    {
      int j = 0;
      Node<T> *p;
      p = Head;         //工作指標p指向頭結點
      while(p && j<i-1) //查詢第i-1個結點
      {
        p = p->next;
        j++;
      }
      if(!p || j>i-1)throw"位置異常";
      else
      {
        Node<T> *s;
        s = new Node<T>;  //建立新節點
        s->data = e;
        s->next = p->next;//結點s鏈到p結點之後
        p->next = s;
      }
    }

    T Delete(int i)//刪除表中第i個元素
    {
          T x;
        Node<T> *p,*q;
        p = Head;  //從頭結點開始查詢
        int j = 0; //計數器初始化
        while(p->next && j<i-1)//p定位到刪除結點的前驅
        {
          p = p->next;
          j++;
        }
        if(!p->next || j>i-1)throw"位置異常";//刪除位置不合理
        else                                 //刪除位置合理
        {
          q = p->next;      //暫存刪除結點位置
          p->next = q->next;//從連結串列中摘除刪除結點
          x = q->data;      //取刪除資料元素的值
          delete q;         //釋放刪除點
          return x;         //返回刪除元素的值
        }
     }

    //獲取第i個元素的值
    T getElem(int i)
    {
      Node<T> *p;     //設定工作指標
      p = Head->next; //從首結點開始
      int j = 1;      //計數器初始化
      while(p && j<i) //定位到第i個元素結點
      {
          p = p->next;
          j++;
      }
      if(!p || j>i)
      {
          throw "位置異常";
      }
      else   //位置合理
      {
        return p->data;
      }
    }

    //在連結串列中查詢值為e的元素
    int Locate(T e)
    {
      int j = 1;
      Node<T> *p;
      p = Head->next;
      while(p && p->data != e)
      {
        p = p->next;
        j++;
      }
      if(!p )//未找到,範圍0
      {
          return 0;
      }
      else  //找到,返回位序
      {
          return j;
      }
    }

    //返回元素e的前驅
    T prior(T e)
    {
      Node<T> *p,*q;
      p = Head;
      q = p->next;
      while(q && q->data != e)
      {
        p = q;
        q = q->next;
      }
      if(p == Head)
      {
        throw "首元素,無前驅";
      }
      else if(!q)
      {
        throw "元素不存在";
      }
      else
      {
        return p->data;
      }
    }
    
    //測表空
    int Empty()
    {
      if(Head->next == NULL)
          return 1; //空表返回1
      else
          return 0; //非空表,返回0
    }

    //測表長
    int Length()
    {
      int len = 0; //計數器初始化
      Node<T> *p;  //設定頭指標
      p=Head;      //指向頭指標
      while(p->next)
      {
        len++;
        p = p->next;
      }
      return len;  //返回表長
    }

    //輸出表元素
    void listDisplay()
    {
      Node<T> *p;
      p = Head->next;
      int i = 1;
      while(p)
      {
        cout<<i<<"\t";
        cout<<p->data<<endl;
        p = p->next;
        i++;
      }
    }
};

/////////////////////////////////////////////////////////////////
//功能:單鏈表類的測試
//////////////////////////////////////////////////////////////////
// linkList_Test.cpp : 定義控制檯應用程式的入口點。
#include "stdafx.h"
#include "linkList.h"
#include "process.h"//exit()
#include<iostream>

using namespace std;
char pause;
typedef int T;

int _tmain(int argc, _TCHAR* argv[])
{
    int i;
    T e,prior_e;
    linkList<int>L;   //建立整形空連結串列
    system("cls");    //執行系統命令,清屏
    int choice;
    do
    {
      cout<<"1-建立連結串列\n";
      cout<<"2-在連結串列第i個位置插入元素\n";
      cout<<"3-刪除連結串列中第i個位置的元素\n";
      cout<<"4-返回第i個元素的值\n";
      cout<<"5-元素定位\n";
      cout<<"6-按值求前驅\n";
      cout<<"7-測表空\n";
      cout<<"8-測表長\n";
      cout<<"9-顯示連結串列\n";
      cout<<"10-退出\n";
      cout<<"Enter choice:";
      cin>>choice;
      switch(choice)
      {
      case 1://建立連結串列
             cout<<"請輸入要建立的連結串列中元素的個數:";
             cin>>i;
             cout<<endl;
             L.createList(i);         
             break;
      case 2://元素插入
           cout<<"請輸入插入的位置";
           cin>>i;
           cout<<endl;
           cout<<"請輸入插入元素的值:";
           cin>>e;
           cout<<endl;
           try
           {
               L.Insert(i,e);
           }
           catch(char* err)
           {
             cout<<err<<endl;
           }
           break;
      case 3://元素刪除
          cout<<"請輸入刪除位置";
          cin>>i;
          cout<<endl;
          try
          {
              e = L.Delete(i);
              cout<<"被刪除元素為:"<<e<<endl;
          }
          catch(char* err)
          {
             cout<<err<<endl;
          }
          cin.get(pause);
          system("pause");
          break;
      case 4://返回第i個元素值
          cout<<"請輸入要查詢的元素位置:";
          cin>>i;
          try
          {
              e = L.getElem(i);
              cout<<"第"<<i<<"個元素值為:"<<e<<endl;
          }
          catch(char* err)
          {
            cout<<err<<endl;
          }
          cin.get(pause);
          system("pause");
          break;
      case 5://按值進行元素查詢
          cout<<"請輸入要查詢的元素值:";
          cin>>e;
          i = L.Locate(e);
          cout<<"查詢元素"<<e<<"在連結串列中的位置為:"<<i<<endl;
          cin.get(pause);
          system("pause");
          break;
      case  6://求元素前驅
          cout<<"請輸入要求前驅元素的值:";
          cin>>e;
          try
          {
              prior_e = L.prior(e);
              cout<<"元素"<<e<<"的前驅值為:"<<prior_e<<endl;
          }
          catch(char *err)
          {
            cout<<err<<endl;
          }
          cin.get(pause);
          system("pause");
          break;
      case 7://測表空
          i = L.Empty();
          if(i)
          {
            cout<<"表空"<<endl;
          }
          else
          {
            cout<<"表不空"<<endl;
          }
          cin.get(pause);
          system("pause");
          break;
      case 8://測表長
          cout<<"連結串列長度為:"<<L.Length()<<endl;
          cin.get(pause);
          system("pause");
          break;
      case 9://遍歷輸出表
          L.listDisplay();
          cout<<endl;
          cin.get(pause);
          system("pause");
          break;
      case 10://退出
          break;
      default://非法選擇
          cout<<"Invalid choice";
          break;
      }       

    }while(choice != 10);
    return 0;
}