日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

理论基础 —— 线性表 —— 单链表

發布時間:2025/3/17 编程问答 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 理论基础 —— 线性表 —— 单链表 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

【實現類】

單鏈表的基本思想就是用指針表示結點之間的邏輯關系,因此要正確的對指針變量、指針、指針所指結點、結點的值進行區分。

設 p 是一個指針變量,則 p 的值是一個指針,若指針?p 指向某個 Node 類型的結點,則該結點用 *p 來表示,并稱?*p 為結點變量,有時為了敘述方便,常將 " 指針變量 " 稱為 " 指針 ",將 " 指針 p 所指的結點 " 稱為 " 結點 p "。

在單鏈表中,結點 p 由兩個域組成,其中,存放數據元素的部分用 p->data 表示,其值是一個數據元素;存放后繼結點地址的指針部分用 p->next 表示,其值是一個指針。

template <class T> struct Node{//結點T data;//數據域Node *next;//指針域 };template <class T> class linkList{ private:Node<T> *first;//頭指針 public:linkList();//無參構造函數linkList(T a[],int n);//有參構造函數~linkList();//析構函數int getLength();//獲取單鏈表的長度T getElement(int i);//獲取單鏈表的第i個元素int getPosition(T x);//獲取單鏈表中值為x的元素序號void insertElement(int i,T x);//在單鏈表中第i個位置插入值為x的元素T deleteElement(int i);//刪除單鏈表的第i的元素void print();//按序號依次輸出單鏈表各元素 };

【構造函數】

1.帶頭結點的構造函數

1)無參構造函數

帶頭結點的無參構造函數,只需要生成一個頭結點,讓頭指針指向頭結點,并將頭結點的指針域置空。

template <class T> linkList<T>::linkList(){//無參構造函數first=new Node<T>;//頭指針指向頭結點first->next=NULL;//頭結點的指針域置為空 }

2)頭插法的有參構造函數

頭插法就是每次將新申請的結點插到頭結點的后面,即始終讓新結點在第一的位置。

使用頭插法建立有參構造函數,首先應建立一個頭結點,讓頭指針指向頭結點,同時將頭結點的指針域置空(與無參構造函數相同),此后,對于 n 個數組元素:

  • 建立一個結點,為結點的數據域賦值
  • 將新結點的指針域指向頭結點的指針域所指向的地址
  • 令頭結點的指針域指向新結點

template <class T> linkList<T>::linkList(T a[],int n){//頭插法的有參構造函數first=new Node<T>;first->next=NULL;for(int i=0;i<n;i++){Node<T> *s=new Node<T>;//建立一個新結點s->data=a[i];//為新結點的數據域賦值s->next=first->next;//將新結點的指針域指向頭結點的指針域所指向的位置first->next=s;//令頭結點的指針域指向新結點} }

3)尾插法的有參構造函數

尾插法就是每次將新申請的結點插到終端結點的后面,即始終讓新結點在最后的位置。

使用尾插法建立有參構造函數,首先應建立一個頭結點,然后再建立一個尾指針,代表單鏈表中最后一個數據元素的位置。此后,對于 n 個數據元素:

  • 建立一個結點,為結點的數據域賦值
  • 將尾指針指針域指向新建立的結點
  • 更改尾指針地址為新結點地址

最后,當單鏈表建立完畢時,將尾指針的指針域置空

template <class T> linkList<T>::linkList(T a[],int n){//尾插法的有參構造函數first=new Node<T>;Node<T> *r=first;//尾指針初始化for(int i=0;i<n;i++){Node<T> *s=new Node<T>;//建立一個新結點s->data=a[i];為新結點數據域賦值r->next=s;//尾指針指針域指向新結點r=s;//更改尾指針地址為新結點地址}r->next=NULL;//單鏈表建立完畢,將尾指針指針域置空 }

2.不帶頭結點的構造函數

1)無參構造函數

不帶頭結點的無參構造函數,只需讓頭指針指向為空。

template <class T> linkList<T>::linkList(){//無參構造函數first=NULL;//頭指針置為空 }

2)頭插法的有參構造函數

頭插法就是每次將新申請的結點插到頭結點的后面,即始終讓新結點在第一的位置。

使用頭插法建立有參構造函數,首先令頭指針置為空(與無參構造函數相同),此后,對于 n 個數組元素:

  • 建立一個結點,為結點的數據域賦值
  • 將新結點的指針域指向頭指針所指向的地址
  • 更改頭指針地址為新結點地址
template <class T> linkList<T>::linkList(T a[],int n){//頭插法的有參構造函數first=NULL;for(int i=0;i<n;i++){Node<T> *s=new Node<T>;//建立一個新結點s->data=a[i];//為新結點的數據域賦值s->next=first;//將新結點的指針域指向頭指針所指向的地址first=s;//更改頭指針地址為新結點地址} }

?3)尾插法的有參構造函數

尾插法就是每次將新申請的結點插到終端結點的后面,即始終讓新結點在最后的位置。

使用尾插法建立有參構造函數,首先令頭指針置為空(與無參構造函數相同),再建立一個尾指針,代表單鏈表中最后一個數據元素的位置,然后建立一個初始結點,將其作為頭結點:

  • 初始結點的數據域賦值為第 1 個數據元素的值
  • 初始結點的指針域指向頭指針指向的地址
  • 更改頭指針地址為初始結點地址
  • 更改尾指針地址為初始結點地址。

此后,對于 n 個數據元素:

  • 建立一個結點,為結點的數據域賦值
  • 將尾指針指針域指向新建立的結點
  • 更改尾指針地址為新結點地址
template <class T> linkList<T>::linkList(T a[],int n){//尾插法的有參構造函數first=null;Node<T> *r=first;//尾指針初始化Node<T> *s=new Node<T>;//建立一個初始結點s->data=a[0];//為初始結點數據域賦值s->next=first;//初始結點指針域指向頭指針的地址first=s;/更改頭指針地址為初始結點地址r=first;//更改尾指針地址為新結點地址for(int i=1;i<n;i++){s=new Node<T>;//建立一個新結點s->data=a[i];為新結點數據域賦值r->next=s;//尾指針指針域指向新結點r=s;//更改尾指針地址為新結點地址} }

?3.帶頭結點和不帶頭結點的單鏈表的比較

操作帶頭結點不帶頭結點
空表first=new node<T>;
first->next=NULL;
first=NULL
在空表中插入一個結點 s

Node<T> *s=new node<T>;

s->next=first->next;
first->next=s

Node<T> *s=new node<T>;

first=s;

插入一個結點,使其成為首元結點

Node<T> *s=new node<T>;

s->next=first->next;
first->next=s

Node<T> *s=new node<T>;

s->next=first;
first=s;

在某一結點 p 后插入結點 s

Node<T> *s=new node<T>;

s->next=p->next;
p->next=s

Node<T> *s=new node<T>;

s->next=p->next;
p->next=s;

【析構函數】

單鏈表中的結點是用 new 申請的,在釋放單鏈表的對象時無法自動釋放這些結點的存儲空間,因此析構函數應將單鏈表中的結點的存儲空間釋放

template<class T> linkList<T>::~linkList(){while(first!=NULL){Node<T> *q=first;//暫存要被釋放的結點first=first->next;//first指向要被釋放的結點的下一個結點delete q;//刪除結點} }

【獲取線性表長度】

求單鏈表的長度時,在將單鏈表掃描同時建立一個累加器,直到掃描到鏈表尾,時間復雜度為 O(n)

template<class T> int linkList<T>::getLength(){int count=0;//累加器Node<T> p=first->next;//工作指針while(p!=NULL){//p不為空p=p->next;//指向下一結點count++;//累加器+1}return count; }

【查找元素】

1.按位查找

按位查找時,不能像順序表按序號訪問,只能從頭指針出發順著 next 域逐個結點向下搜索

  • 工作指針 p、位置累加器初始化
  • 直到 p 為空或指向第 i 個節點:工作指針后移、位置累加器+1
  • 若 p 為空,則第 i 個元素不存在,拋出位置異常;否則查找成功,返回節點 p 的數據元素
template<class T> T linkList<T>::getElement(int i){int pos=1;//位置累加器Node<T> p=first->next;//工作指針while(p!=NULL&&pos<i){//p不為空且位置小于ip=p->next;//指向下一結點pos++;//累加器+1}if(p==NULL)throw "查找位置異常";elsereturn p->data;//返回數據元素 }

2.按值查找

按值查找時,需要對單鏈表中的元素依次進行比較,時間復雜度為 O(n)

  • 工作指針 p、位置累加器初始化
  • 直到 p 為空:工作指針后移、位置累加器+1
  • 若在循環中找到元素,則返回序號,即位置累加器的值;若退出循環,則查找失敗,單鏈表中沒有相關值
template<class T> int linkList<T>::getPosition(T x){int pos=1;//位置累加器Node<T> p=first->next;//工作指針while(p!=NULL){//p不為空if(p->data==x)//找到值return pos;//返回位置p=p->next;//指向下一結點pos++;//累加器+1}return 0;//查找失敗 }

【插入操作】

1.帶頭結點的插入

在單鏈表中的第 i 個位置插入元素,需要先找到第 i-1 個元素,若找不到則拋出位置異常,若找到則將新結點插入位置 i

  • 工作指針 p 、位置計數器初始化
  • 查找第 i-1 個節點,并使工作指針 p 指向該節點
  • 若查找不成功(P==NULL),說明位置錯誤,拋出位置異常,否則生成一個元素值為 x 的新節點 s,并將 s 插入到 p 之后
template<class T> void linkList<T>::insertElement(int i,T x){int pos=0;//位置累加器Node<T> *p=first->next;//工作指針while(p!=NULL&&pos<i-1){//p不為空且位置小于i-1p=p->next;//指向下一結點pos++;//累加器+1}if(p==NULL)throw "插入位置異常";else{Node<T> *s=new Node<T>;//新申請一個結點s->data=x;//新結點數據域賦值為xs->next=p->next;//新結點s指向工作結點p之后的結點p->next=s;//工作結點p指向新結點s} }

2.不帶頭結點的插入

不帶頭結點的插入與帶頭結點的插入十分相似,區別僅在于當插入位置是第一個位置時

template<class T> void linkList<T>::insertElement(int i,T x){if(i==1){//若在第一個位置插入Node<T> *s=new Node<T>;//新申請一個結點s->next=first;//新結點的指針域指向頭指針所指向的結點first=s;//令頭指針指向新結點return;}int pos=1;//位置累加器Node<T> *p=first;//工作指針while(p!=NULL&&pos<i-1){//p不為空且位置小于i-1p=p->next;//指向下一結點pos++;//累加器+1}if(p==NULL)throw "插入位置異常";else{Node<T> *s=new Node<T>;//新申請一個結點s->data=x;//新結點數據域賦值為xs->next=p->next;//新結點s指向工作結點p之后的結點p->next=s;//工作結點p指向新結點s} }

【刪除操作】

在單鏈表中刪除第 i 個位置的元素,需要先找到第 i-1 個元素,若找不到則拋出位置異常,若找到將第 i-1 個結點指針域所指向的結點刪除

  • 工作指針 p 、位置計數器初始化
  • 查找第 i-1 個節點,并使工作指針 p 指向該節點
  • 若查找不成功(P==NULL),說明位置錯誤,拋出位置異常,否則將被刪結點從鏈表中摘下并釋放存儲空間

template<class T> T linkList<T>::deleteElement(int i){int pos=0;//位置累加器Node<T> *p=first;//工作指針while(p!=NULL&&pos<i-1){//p不為空且位置小于i-1p=p->next;//指向下一結點pos++;//累加器+1}if(p==NULL||p->next!=NULL)//p不存在或p的后繼結點不存在throw "刪除位置異常";else{Node<T> *s=p->next;//暫存被刪結點T x=p->data;p->next=s->next;//摘鏈delete s;//釋放空間return x;} }

【遍歷輸出】

遍歷輸出即按照單鏈表的指針指向依次輸出線性表各元素

  • 建立一個臨時結點,令臨時結點地址為頭指針指向的結點
  • 當臨時結點不為空時,輸出數據域,并指向下一結點
template <class T> void LinkList<T>:: print(){//依次輸出線性表各元素Node<T> *p;//新建一個臨時結點p=first->next;//令臨時結點地址為頭指針所指向的結點while(p!=NULL){//當臨時結點不為空時cout<<(p->data)<<endl;//輸出數據域p=p->next;//指向下一結點} }

?

總結

以上是生活随笔為你收集整理的理论基础 —— 线性表 —— 单链表的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。