单链表的插入,删除,查找,转置

单链表的定义

线性表的链式存储又称为单链表,它是指通过任意一组的存储单元来存储线性表中的数据元素。 在单链表中,每个节点包含一个指向链表下一节点的指针。链表最后一个节点的指针字段的值为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.运行截图

这里写图片描述

持续更新中~~

猜你喜欢

转载自blog.csdn.net/qq_41317652/article/details/82707705