天天看點

删除單鍊上資料域值最小的節點_資料結構(二)| 一文搞懂單連結清單的基本操作和實作...

https://www.cnblogs.com/953-zjf/p/LinkList.html

(一)連結清單的幾個基本概念

頭節點:是單連結清單的頭 ,是一個特殊的節點,隻有指針域,沒有資料域。

删除單鍊上資料域值最小的節點_資料結構(二)| 一文搞懂單連結清單的基本操作和實作...

節點:由兩部分構成,第一部分是資料域,存儲的是該節點的内容,第二部分是指針域,用來存儲下一節點的位址,通過改位址可以通路下一個節點。

删除單鍊上資料域值最小的節點_資料結構(二)| 一文搞懂單連結清單的基本操作和實作...

單連結清單:由頭節點和若幹節點組成的連結清單。

删除單鍊上資料域值最小的節點_資料結構(二)| 一文搞懂單連結清單的基本操作和實作...

這是一個有三個節點的連結清單。

(二)連結清單的存儲結構

(1)從上篇文章我們得知順序表在計算機中存儲的位置是連續的,就像宿舍樓一層的房間,都是相鄰的,但連結清單不一樣,連結清單不一定是相鄰的,隻不過每一個節點都會存儲下一個節點的位址。比如說,小明有小紅的位址,小紅呢有小白的位址,小白又有小蘭的位址,小黑有小明的位址,他們五個是一個班的,是以他們之間就形成了一個關系:

删除單鍊上資料域值最小的節點_資料結構(二)| 一文搞懂單連結清單的基本操作和實作...

這就是一個單連結清單的結構,單是指隻有前驅節點有後繼節點的位址,隻有單向性,當然也有雙向連結清單,後面遇到了我們再講。

(2)上面是我們自己抽象化的一個連結清單,在計算機中的存儲結構是下圖: 

删除單鍊上資料域值最小的節點_資料結構(二)| 一文搞懂單連結清單的基本操作和實作...

(三)代碼分析

(1)頭檔案

#include      //基本的輸入輸出using namespace std;   //聲明命名空間#include     //字元串頭檔案
           

(2)預處理

#define OK 1#define ERROR 0#define ElemType int
           

(3)建立節點,很明顯,這裡要用到結構體,結構體有兩個成員,一個是資料域,一個是指針域。

typedef struct LNode{    struct LNode *next;   //節點指針域    string data;          //節點資料域}*LinkList,LNode;          //一個是結構體指針,一個是結構體名稱
           

(4)初始化函數,建立一個頭節點,并将指針域置空。

ElemType Init_Linklist(LinkList &L)  //初始化連結清單{    L = new LNode;                  //建立一個頭節點    L->next = NULL;                 //并将頭節點的指針域置空    return OK;}
           

(5)輸對外連結表函數,這個函數呢,是将單連結清單中的每個元素按順序輸出,為了美觀,用"->"隔開。 實作步驟: ①定義一個節點指針,指向第一個節點。(注意:這裡的第一個節點是頭節點之後的第一個。) ②while判斷目前節點是否為空,如果不是空,就輸出該節點内容,然後指針下移,下面的if是最後一個節點不輸出"->",這樣連結清單看起來會更美觀。

void Printf_LNode(LinkList L)   //周遊輸對外連結表内容{    cout<<"連結清單内容:";    LNode *p = L->next;            //節點指針,用來周遊節點    while(p)    {        cout<data;             //輸出節點的資料域        p = p->next;        if(p)                     //判斷下一個節點是否為空,如果是就不輸出"->"        {            cout<<"->";        }    }    cout<<endl;}
           

(6)前插法建立連結清單,即每次在第一個節點的位置插入新節點。咱們先自己想一下這個過程,首先,我們要建立一個節點吧,然後将新節點的指針域指向下一個節點,再把上一個節點的指針域指向自己,不就插入成功了嘛。看一下圖檔:

删除單鍊上資料域值最小的節點_資料結構(二)| 一文搞懂單連結清單的基本操作和實作...

實作步驟: ①輸出提醒,并得到你要建立節點的個數n。 ②建立一個節點指針,便于後面改指針的操作。 ③初始化頭節點,并将指針域置空。 ④要建立n個節點,自然需要循環n次,首先開辟一個新節點,并讓p指向新節點,将新節點的指針指向下一個節點,再讓上一個節點指向自己,然後在輸入該節點的内容。 ⑤輸對外連結表。

void Create_LinkList_h(LinkList &L)    //前插法建立單連結清單{    int n;    cout<<"請輸入你要建立的連結清單的結點個數:";    cin>>n;    LNode *p;    L = new LNode;        //初始化頭節點    L->next = NULL;    cout<<"将要采用頭插法建立單連結清單,請逆序輸入"<"個節點内容:";    for(int i = 0;i < n;i++)    //循環建立節點    {        p = new LNode;        p->next = L->next;        L->next = p;        cin>>p->data;    }    Printf_LNode(L);          //輸對外連結表内容}
           

(7)後插法建立連結清單,尾插法是将每個元素插在最後,故稱為後插法。與前插法大緻相同,不過比前插法多一個節點指針,首先建立一個節點,然後自己的指針域為空,因為自己已經是最後一個節點了,然後讓上一個節點指向自己,然後插入成功。 實作步驟: ①首先得到你要輸入的節點個數n ②初始化頭節點 ③定義一個節點指針r,并指向L ④循環n次,每一次都先申請一個節點,輸入節點内容,因為是後插,是以每一個節點的指針域都指向空,然後再讓上一個節點指向自己,然後r後移一個節點。

删除單鍊上資料域值最小的節點_資料結構(二)| 一文搞懂單連結清單的基本操作和實作...
void Create_LinkList_r(LinkList &L)   //尾插法建立連結清單{    int n;                              //節點個數    cout<<"請輸入你要建立的連結清單的結點個數:";    cin>>n;    L = new LNode;                    //初始化頭節點    L->next = NULL;    LNode *r = L;    cout<<"将要采用尾插法建立單連結清單,請輸入"<"個節點内容:";    for(int i = 0;i < n;i++)    //循環建立節點    {        LNode *p;        p = new LNode;        cin>>p->data;        p->next = NULL;        r->next = p;        r = p;    }    Printf_LNode(L);}
           

(8)取值,通過輸入的位置, 周遊連結清單,找到對應位置的值,然後指派即可。 實作步驟: ①首先輸入你要取得元素的位置 ②定義一個新的節點指針,并指向頭節點的下一個節點,同時呢也定義一個j,用來記錄節點的值。 ③用while循環,讓指針連續下移到相應位置,同時判斷j的值是否達到n。 ④如果已經移到空節點了,或者說j已經大于n了,就表明越界了。 ⑤如果沒有越界,就指派即可。

ElemType Get_ElemType(LinkList L,string &name){    int n;                      //元素位置    cout<<"請輸入你要取得元素的位置:";    cin>>n;    LNode *p = L->next;    //建立節點指針,并指向下一個節點    int j = 1;    while(p&&j//指針移到要取得位置    {        p = p->next;        j++;    }    if(!p || j>n)           //判斷是否越界    {        return ERROR;    }    name = p->data;        //取值}
           

(9)插入節點,其實也就是先開辟一個節點,然後讓新節點指向下一個節點,再讓新節點的上一個節點指向自己,就插入成功了。 實作步驟: ①首先得到你要插入的位置 ②定義一個節點指針,指向第一個節點 ③指針連續下移,移到n-1的節點。 ④判斷是否越界 ⑤建立一個節點和一個指向新節點的指針s,然後輸入插入的節點的值。 ⑥改指針,将上一個節點的指針賦給新節點,然後讓上一個節點指向自己,就插入成功了。

ElemType Insert_LNode(LinkList &L)   //插入節點函數{    int n;      //插入得位置    cout<<"請輸入你要插入的位置:";    cin>>n;    LNode *p = L->next;    int j = 1;    while(p&&j1))       {        p = p->next;        j++;    }    if(!p || j > (n - 1))  //判斷是否越界    {        return ERROR;    }    LNode *s;         //指向建立節點的指針    s = new LNode;    cout<<"請輸入你要插入的元素:";    cin>>s->data;    //輸入新節點的資料域内容    s->next = p->next;    p->next = s;    Printf_LNode(L);   //輸出單連結清單}
           

(10)删元素,其實跟之前插元素的實作差不多,都是先移到你要删除的位置,然後把你想要删除節點的指針域賦給前一個節點,然後釋放節點即可。 實作步驟: ①輸出一邊目前連結清單的内容,然後挑選并得到你要删除的位置,同時定義一個節點指針q。 ②定義一個節點指針指向第一個節點,并定義一個計數變量j。 ③指針p連續下移到要删除的元素的前一個位置,然後在把該節點的指針域(q = p->next),賦給節點指針q,這樣q就指向了我們要删除的節點,然後讓q指向我們要删除的節點的下一個節點,然後釋放q節點即可。

删除單鍊上資料域值最小的節點_資料結構(二)| 一文搞懂單連結清單的基本操作和實作...
ElemType Del_LNode(LinkList &L)  //删除節點函數{    int n;    LNode *q;       //首先定義一個節點指針    Printf_LNode(L);    cout<<"請輸入你要删除的位置:";    cin>>n;    LNode *p = L->next;    int j = 1;    while(p&&(j< n - 1))  //指針下移    {        p = p->next;        ++j;    }    if(!p || j > (n - 1))  //判斷是否越界    {        return ERROR;    }    q = p->next;    p->next = q->next;    delete q;    Printf_LNode(L);}
           

(11)菜單函數,隻是一些普通的輸出,就不用解釋了吧。

void Menu()   //菜單函數{    cout<<"<<<<<<<<<<<<<<>>>>>>>>>>>>>>"<<endl;    cout<<"1.初始化單連結清單"<<endl;    cout<<"2.頭插法建立一個單連結清單"<<endl;    cout<<"3.尾插法建立一個單連結清單"<<endl;    cout<<"4.取單連結清單中的某個元素"<<endl;    cout<<"5.在單連結清單某個位置插入元素"<<endl;    cout<<"6.在單連結清單删除某個位置的元素"<<endl;    cout<<"7.輸對外連結表内容"<<endl;    cout<<"8.菜單"<<endl;    cout<<"9.退出系統!"<<endl;    cout<<"輸入對應選項,執行對應操作"<<endl;}
           

(12)主函數:首先建立一個連結清單指針,輸出菜單,然後進入while循環,通過switch輸入不同的選項進入不同的case,然後執行不同的函數,這裡為了能夠退出系統(跳出循環)使用了goto語句來結束循環。這裡需要特别說明的可能就是case 4和case 5,定義了兩個标志變量,用來記錄程式退出的值,看是否出錯。

int main(){    LinkList La;  //連結清單指針    int select;    Menu();    while(1)   //循環輸入選項    {        cout<<"請輸入選項:";        cin>>select;        switch(select)   //判斷選項,并執行對應的函數        {        case 1:            {                Init_Linklist(La);                cout<<"初始化後單連結清單為空,要想進行操作,請先建立一個單連結清單"<<endl;                Create_LinkList_h(La);                break;            }        case 2:            {                Create_LinkList_h(La);                break;            }        case 3:            {                Create_LinkList_r(La);                break;            }        case 4:            {                int flag;         //标志變量,用來記錄退出碼,用來判斷是否為正常退出                string name;               flag = Get_ElemType(La,name);               if(!flag)               {                   cout<<"取出失敗,越界!"<<endl;               }                cout<endl;                break;            }        case 5:            {                int flag;                flag = Insert_LNode(La);    //标志變量,用來記錄退出碼,用來判斷是否為正常退出                if(!flag)                {                    cout<<"插入失敗,越界!"<<endl;                }                break;            }        case 6:            {                Del_LNode(La);                break;            }        case 7:            {                Printf_LNode(La);                break;            }        case 8:            {                Menu();                break;            }        case 9:            {                cout<<"多謝使用"<<endl;                goto unloop;      //使用goto語句,跳轉,使程式結束            }        default:        {            cout<<"輸入有誤!"<<endl;            break;        }        }    }    unloop:return 0;      //跳轉到程式結束語句}
           

(四)完整代碼

#include      //基本的輸入輸出using namespace std;   //聲明命名空間#include     //字元串頭檔案#define OK 1#define ERROR 0#define ElemType inttypedef struct LNode{    struct LNode *next;   //節點指針域    string data;          //節點資料域}*LinkList,LNode;          //一個是結構體指針,一個是結構體名稱ElemType Init_Linklist(LinkList &L)  //初始化連結清單{    L = new LNode;                  //建立一個頭節點    L->next = NULL;                 //并将頭節點的指針域置空    return OK;}void Printf_LNode(LinkList L)   //周遊輸對外連結表内容{    cout<<"連結清單内容:";    LNode *p = L->next;            //節點指針,用來周遊節點    while(p)    {        cout<data;             //輸出節點的資料域        p = p->next;        if(p)                     //判斷下一個節點是否為空,如果是就不輸出"->"        {            cout<<"->";        }    }    cout<<endl;}void Create_LinkList_h(LinkList &L)    //前插法建立單連結清單{    int n;    cout<<"請輸入你要建立的連結清單的結點個數:";    cin>>n;    LNode *p;    L = new LNode;        //初始化頭節點    L->next = NULL;    cout<<"将要采用頭插法建立單連結清單,請逆序輸入"<"個節點内容:";    for(int i = 0;i < n;i++)    //循環建立節點    {        p = new LNode;        p->next = L->next;        L->next = p;        cin>>p->data;    }    Printf_LNode(L);          //輸對外連結表内容}void Create_LinkList_r(LinkList &L)   //尾插法建立連結清單{    int n;                              //節點個數    cout<<"請輸入你要建立的連結清單的結點個數:";    cin>>n;    L = new LNode;                    //初始化頭節點    L->next = NULL;    LNode *r = L;    cout<<"将要采用尾插法建立單連結清單,請輸入"<"個節點内容:";    for(int i = 0;i < n;i++)    //循環建立節點    {        LNode *p;        p = new LNode;        cin>>p->data;        p->next = NULL;        r->next = p;        r = p;    }    Printf_LNode(L);}ElemType Get_ElemType(LinkList L,string &name){    int n;                      //元素位置    cout<<"請輸入你要取得元素的位置:";    cin>>n;    LNode *p = L->next;    //建立節點指針,并指向下一個節點    int j = 1;    while(p&&j//指針移到要取得位置    {        p = p->next;        j++;    }    if(!p || j>n)           //判斷是否越界    {        return ERROR;    }    name = p->data;        //取值}ElemType Insert_LNode(LinkList &L)   //插入節點函數{    int n;      //插入得位置    cout<<"請輸入你要插入的位置:";    cin>>n;    LNode *p = L->next;    int j = 1;    while(p&&j1))       {        p = p->next;        j++;    }    if(!p || j > (n - 1))  //判斷是否越界    {        return ERROR;    }    LNode *s;         //指向建立節點的指針    s = new LNode;    cout<<"請輸入你要插入的元素:";    cin>>s->data;    //輸入新節點的資料域内容    s->next = p->next;    p->next = s;    Printf_LNode(L);   //輸出單連結清單}ElemType Del_LNode(LinkList &L)  //删除節點函數{    int n;    LNode *q;       //首先定義一個節點指針    Printf_LNode(L);    cout<<"請輸入你要删除的位置:";    cin>>n;    LNode *p = L->next;    int j = 1;    while(p&&(j< n - 1))  //指針下移    {        p = p->next;        ++j;    }    if(!p || j > (n - 1))  //判斷是否越界    {        return ERROR;    }    q = p->next;    p->next = q->next;    delete q;    Printf_LNode(L);}void Menu()   //菜單函數{    cout<<"<<<<<<<<<<<<<<>>>>>>>>>>>>>>"<<endl;    cout<<"1.初始化單連結清單"<<endl;    cout<<"2.頭插法建立一個單連結清單"<<endl;    cout<<"3.尾插法建立一個單連結清單"<<endl;    cout<<"4.取單連結清單中的某個元素"<<endl;    cout<<"5.在單連結清單某個位置插入元素"<<endl;    cout<<"6.在單連結清單删除某個位置的元素"<<endl;    cout<<"7.輸對外連結表内容"<<endl;    cout<<"8.菜單"<<endl;    cout<<"9.退出系統!"<<endl;    cout<<"輸入對應選項,執行對應操作"<<endl;}int main(){    LinkList La;  //連結清單指針    int select;    Menu();    while(1)   //循環輸入選項    {        cout<<"請輸入選項:";        cin>>select;        switch(select)   //判斷選項,并執行對應的函數        {        case 1:            {                Init_Linklist(La);                cout<<"初始化後單連結清單為空,要想進行操作,請先建立一個單連結清單"<<endl;                Create_LinkList_h(La);                break;            }        case 2:            {                Create_LinkList_h(La);                break;            }        case 3:            {                Create_LinkList_r(La);                break;            }        case 4:            {                int flag;         //标志變量,用來記錄退出碼,用來判斷是否為正常退出                string name;               flag = Get_ElemType(La,name);               if(!flag)               {                   cout<<"取出失敗,越界!"<<endl;               }                cout<endl;                break;            }        case 5:            {                int flag;                flag = Insert_LNode(La);    //标志變量,用來記錄退出碼,用來判斷是否為正常退出                if(!flag)                {                    cout<<"插入失敗,越界!"<<endl;                }                break;            }        case 6:            {                Del_LNode(La);                break;            }        case 7:            {                Printf_LNode(La);                break;            }        case 8:            {                Menu();                break;            }        case 9:            {                cout<<"多謝使用"<<endl;                goto unloop;      //使用goto語句,跳轉,使程式結束            }        default:        {            cout<<"輸入有誤!"<<endl;            break;        }        }    }    unloop:return 0;      //跳轉到程式結束語句}
           

(五)運作結果

删除單鍊上資料域值最小的節點_資料結構(二)| 一文搞懂單連結清單的基本操作和實作...

程式在健壯性方面還有很多不足,各位大神如果有什麼好的想法或者發現我的某些錯誤,歡迎指正!最後希望大家給我一個支援,謝謝!

繼續閱讀