C++連結串列操作總結和常見連結串列操作
阿新 • • 發佈:2019-02-18
一、連結串列的定義
連結串列是一種動態資料結構,他的特點是用一組任意的儲存單元(可以是連續的,也可以是不連續的)存放資料元素。連結串列中每一個元素成為“結點”,每一個結點都是由資料域和指標域組成的,每個結點中的指標域指向下一個結點。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; }