1. 程式人生 > >單鏈表的插入,刪除,查詢,轉置

單鏈表的插入,刪除,查詢,轉置

單鏈表的定義

線性表的鏈式儲存又稱為單鏈表,它是指通過任意一組的儲存單元來儲存線性表中的資料元素。 在單鏈表中,每個節點包含一個指向連結串列下一節點的指標。連結串列最後一個節點的指標欄位的值為NULL,提示連結串列後面不再有其它節點。它是非隨機存取的儲存結構,操作時只能從表頭開始遍歷。

這裡寫圖片描述
通常用 “頭指標” 標識一個單鏈表,頭指標為“NULL“ 表示空表,為了操作上的方便,在單鏈表的第一個節點前附加一個節點,稱頭節點 ,引入頭節點的兩個優點:
1)由於開始節點的位置被存放被存放在頭節點的指標域,所以再連結串列第一個位置的操作和在表的其他位置上操作一致,無需特殊對待
2)無論連結串列是否空,其頭指標是指向頭節點的非空指標(空表中頭節點的指標域為空),因此空表的和非空表的處理也就統一了
因此以下討論基於帶有頭節點的單鏈表

採用資料結構:

typedef struct node{
    ElemType data;
    struct node * next;
}node;

1.建立

1)頭插法

node *creat(){
    node *head=new node,*p,*pre;
    head->next =NULL;  //original
    pre=head; 
    int x;
    scanf("%d",&x);
    while(x!=-1){    
        p=new node;
        p->data =x;
        p->next
=pre->next ; //每個節點插入O(1),總O(n) pre->next =p; scanf("%d",&x); } return head; }

頭插法雖簡單,但生成連結串列中節點的次序與輸入順序不一致,若希望兩者次序一致,可採用頭插法。

2)尾插法

node *creat(){
    node *head=new node;
    head->next =NULL;
    int x;
    cin>>x;
    node *pre=head,*p;
    while
(x!=-1){ p=new node; p->data =x; p->next=NULL; pre->next =p; pre=p; cin>>x; } return head; }

2.查詢

1)按序號查詢
2)按值查詢
這兩種都比較簡單,直接遍歷連結串列搜尋,符合條件時輸出,此不贅述

3.刪除節點

1)按序號刪除

關鍵點:遍歷查詢單鏈表中待刪除節點的前驅

node* Del_node_id( node *head,int i){
    node *p=head,*q;
    int count=0;
    while(p->next !=NULL){
        count++;
        q=p->next; //q前驅 
        if(count==i){
            p->next =q->next;
            delete q;
            return head;
        } 
        p=p->next;  
    }
      //i 不符合實際要求 
      printf("你的刪除元素位置有錯!\n");
    return head;
} 

2)按元素值刪除

node *Del_node_value(node *head,int value){
    node *p=head,*q;
    while(p->next !=NULL){ 
        q=p->next ;  //q前驅節點
        if(p->next->data==value  ){ 
            p->next =q->next ;
            delete q;
            return head; 
        }
        p=p->next ; //指標後移
    }
        printf("此連結串列沒有值為value的節點!\n");   
    return head;
}

刪除過程注意不要斷鏈即可

那麼問題來了:如何刪除單鏈表中的重複節點(保留第一個重複節點)

思路1:兩層迴圈,暴力列舉刪除,時間複雜度O(n^2),空房間複雜度O(1)

void Del_linklist(node * H){
    node *p,*q,*r;
    p=H->next; 
    if(p!=NULL) //非空連結串列
        while(p->next){  //外層,需大於1個節點
            q=p-next;
            while(q){ //內層,p的下一個節點開始遍歷
                if(q->next->data==p->data){ //刪除符合條件的節點
                    r=q->next;
                    q->next=r->next;
                    delete r;
                }
                q=q->next;
            }
            p=p->next;
        }
 } 

思路2:改進第一種做法,採用空間換時間,使用輔助陣列記錄連結串列已出現的節點,從而只對連結串列進行一邊掃描,邊遍歷邊標記,符合刪除條件,則delete。時間複雜度O(n),空房間複雜度O(n)

node *delList(node *head){
    node *r,*p=head->next;
    r=p;
    if(p==NULL) return NULL;
    fill(vis,vis+1000,false);
    while(p!=NULL){
        if(vis[p->data]==true){
        r->next =p->next ;
        delete p;
        p=r->next ;
    }
    else{
        vis[p->data]=1;
        r=p;
        p=p->next ; 
      }
    }
    return head;
}

類似問題:如何刪除連結串列中重複元素(重複元素全部刪除)

提示:空間換時間,採用Hash[ ]雜湊,一遍掃描標記,一遍掃描刪除,只需兩次遍歷。時間複雜度O(n),空房間複雜度O(n)。

node *del(node *head){
    fill(hash,hash+maxn,0);
    node *r,*p=head->next;
    r=head;
    if(p==NULL) return NULL;
    while(p){ //一遍掃描標記
        hash[p->data]++;
        //cout<<p->data <<hash[p->data]<<endl; 
        p=p->next ;
    }
    //開始開始嘍
    p=r-next; 
    while(p!=NULL){ //一遍掃描刪除
        if(hash[p->data]>1){
            r->next =p->next ;
            delete p;
            p=r->next ;
        }else{
            r=p;
            p=p->next ; 
        }
    }
    return head;
}

4.插入節點

關鍵點:找到待插入節點位置的前驅

node* Insert_linklist(node *head,int i,int value){
    node *p=head,*q;
    int count=0;
    while(p->next !=NULL){
        count++;
        if(count==i) //找待插入節點的前驅指標 p 
        break; 
        p=p->next;
    } //開始插入
    q=new node;
    q->data =value;
    q->next =p->next ;
    p->next =q;
    return head;
} 

5.逆置連結串列

關鍵點:不斷遍歷連結串列,將後一個節點的next指向前一個節點
最後頭節點掛到原連結串列的尾部

node* Transpose_linklist(node *H){
    node*p,*q,*pr;
    p=H->next ;
    H->next =NULL; //摘除頭節點 
    q=NULL;  
    while(p){
        pr=p->next;
        p->next=q; //後一個節點的next指向前一個節點
        q=p;   //尾指標為空 
        p=pr;  //指標後移 
     } 
     H->next =q; //頭節點掛到原連結串列的尾部
     printf("轉置後連結串列:\n");
 } 

6.列印連結串列

void output_linklist(node* H){
    node *p=H->next ;
    while(p){
        printf("%2d",p->data );
        p=p->next ;
    }
}

7.程式碼

#include<cstdio>
#define ElemType int
struct node{
    ElemType data;
    node * next;
};
//尾插法建立單鏈表 
node *creat1( ){
    node*head,*pre,*p;
    int x;
    scanf("%d",&x);
    head=new node;
    head->next=NULL;
    pre=head;
    while(x!=-1){
        p=new node;     
        p->data=x;
        p->next=NULL;
        pre->next=p;
        pre=p;
        scanf("%d",&x); 
    }
    return head;
}
//頭插法建立單鏈表
/*  
node *creat2(){
 *  node *head=new node,*p,*pre;
 *  head->next =NULL;  //original
 *  pre=head; 
 *  int x;
 *  scanf("%d",&x);
 *  while(x!=-1){    
 *      p=new node;
 *      p->data =x;
 *      p->next =pre->next ;  //每個節點插入O(1),總O(n) 
 *      pre->next =p;
 *      scanf("%d",&x); 
 *  }
 *  return head;
}*
*/ 
//轉置單鏈表 
node* zhuanzhi_linklist(node *H)
{
    node*p,*q,*pr;
    p=H->next ;
    H->next =NULL; //摘除頭節點 
    q=NULL;  
    while(p)
    {
        pr=p->next;
        p->next=q;
        q=p;   //尾指標為空 
        p=pr;  //指標後移 
     } 
     H->next =q; 
     printf("轉置後連結串列:\n");
 } 
//刪除單鏈表中重複的節點,時間複雜度o(n^2)
//hash[]後刪除效率高 
void Del_linklist(node * H){
    node *p,*q,*r;
    p=H->next; 
    if(p!=NULL)
        while(p->next) {
            q=p;
            while(q->next)
            {
                if(q->next->data==p->data)
                {
                    r=q->next;
                    q->next=r->next;
                    delete r;
                }
                q=q->next;
            }
            p=p->next;
        }
 } 
//刪除某位置節點
node* Del_node_id( node *head,int i){
    node *p=head,*q;
    int count=0;
    while(p->next !=NULL){
        count++;
        q=p->next; //q前驅 
        if(count==i){
            p->next =q->next;
            delete q;
            return head;
        } 
        p=p->next;  
    }
      //i不符合實際要求 
      printf("你的刪除元素位置有錯!\n");
    return head;
} 
//刪除值為value的節點
node *Del_node_value(node *head,int value){
    node *p=head,*q;
    while(p->next !=NULL){
        q=p->next ;
        if(p->next->data==value  ){
            p->next =q->next ;
            delete q;
            return head; 
        }
        p=p->next ;
    }
        printf("此連結串列沒有值為value的節點!\n");   
    return head;
}
//新增 n 個節點
node *Add_linklist(node *head){
    node *p=head,*q;
    while(p->next!=NULL){   //此處的 p 應指向尾節點,方便新增新的節點 
        p=p->next ;
    }
    int x;
    scanf("%d",&x);
    while(x!=-1){
        q=new node;
        q->data =x;
        q->next =NULL;
        p->next =q;
        p=q;
        scanf("%d", &x );
        }
    return head;
} 
//插入節點
node* Insert_linklist(node *head,int i,int value){
    node *p=head,*q;
    int count=0;
    while(p->next !=NULL){
        count++;
        if(count==i) //找帶插入節點位置的前驅指標 p 
        break; 
        p=p->next;
    } 
    q=new node;
    q->data =value;
    q->next =p->next ;
    p->next =q;
    return head;
} 
//列印節點 
void output_linklist(node* H)
{
    node *p=H->next ;
    while(p)
    {
        printf("%2d",p->data );
        p=p->next ;
    }
}
int main(){
    node*head=creat1();
    printf("列印連結串列:\n"); 
    output_linklist(head);
    printf("\n");
    Transpose_linklist(head);
    output_linklist(head);
    printf("\n");
    Del_linklist(head);
    printf("刪除重複節點,保留第一個:\n");
    output_linklist(head);
    printf("\n");
    printf("輸入尾部要新增節點,-1表示結束:\n");
    head=Add_linklist(head);
    output_linklist(head);
    printf("\n");
    int i,value;
    printf("輸入要插入的元素位置及元素值:\n");
    scanf("%d%d",&i,&value);
    Insert_linklist(head, i, value);
    output_linklist(head);
    printf("\n");               
    printf("please input del posttion:\n");
    int j;
    scanf("%d",&j);
    Del_node_id(head, j);
    output_linklist(head);
    printf("\nplease input del value:\n");
    scanf("%d",&value);
    Del_node_value(head, value);
    output_linklist(head);
    return 0;
}

6.執行截圖

這裡寫圖片描述

持續更新中~~