无头结点的单链表一系列操作

 

无头结点的单链表的一系列操作

没有头结点的链表,C++实现其初始化,建立,插入,删除,查询,计算长度,输出。感觉没有头结点好多操作都变得复杂了那么一丢丢。

目录

 

无头结点的单链表的一系列操作

初始化

建立

查找

插入

删除

计算链表长度

打印链表


初始化

typedef int datatype;
struct nodes{
    datatype data;
    nodes *next;
};
struct Lists{
    nodes *head;
};
//初始化
Lists init(){
    Lists List;
    List.head=NULL;
    return List;
}

建立

尾插法

//无头结点的尾插法
void CreatListI(Lists *List){
    datatype num;
    cout<<"输入数据元素,当数据元素为-1时结束"<<endl;
    while(cin>>num&&num!=-1){
        nodes *temp=(nodes*)malloc(sizeof(nodes));
        temp->data=num;
        temp->next=NULL;
        nodes *tail;
        if(List->head==NULL){
            List->head=temp;
            tail=List->head;
        }
        else {
            tail->next=temp;
            tail=temp;
        }
    }
}

尾插法实现链表的建立,尾插法主要是通过一个指向链表最后一个结点的指针tail,每次插入都插在tail->next,并更新tail,注意插入第一个结点时需要特殊操作一波。

头插法

//无头结点的头插法
void CreatListII(Lists *List){
    datatype num;
    cout<<"输入数据元素,当数据元素为-1时结束输入"<<endl;
    while(cin>>num&&num!=-1){
        nodes *node=(nodes*)malloc(sizeof(nodes));
        node->data=num;
        node->next=List->head;
        List->head=node;
    }
}

头插法实现链表的建立。头插法是把需要插入的结点插到链表的第一个位置,插入完成后链表的顺序和插入的顺序是相反的。头插法和尾插法,感jio就是“茴”的多种写法。。。

查找

按序号查找

//按序号查找,查找第n位并返回第n位的地址,找不到返回NULL
nodes* SearSeque(Lists *List,int n){

    nodes *temp=List->head;
    int i=1;
    while(temp!=NULL){
        if(i==n)return temp;
        i++;
        temp=temp->next;
    }
    return NULL;
}

按序号查找,查找第n个位置的元素并返回第n位的地址,找不到该位置就返回NULL。因为没有头结点,所以head指针指向的就是第一个结点,计数器i初始化为1.

按值查找

//按值查找,查找数据元素为x的结点并返回找到的第一个结点的地址,找不到返回NULL
nodes *SearValue(Lists *List,datatype x){
    nodes *temp=List->head;
    while(temp!=NULL){
        if(temp->data==x){
            return temp;
        }
        temp=temp->next;
    }
    return NULL;
}

按值查找,查找数据元素为x的结点并返回找到的第一个结点的地址,找不到返回NULL。把这个按值查找改进为返回找到的第一个结点前一个元素的地址,就可以运用到按值删除里了。

插入

前插法

//前插法插入,插入到第n位前
void InsertListI(Lists *List,int n,datatype x){
    nodes *node=(nodes*)malloc(sizeof(nodes));
    node->data=x;
    if(n==1){
        node->next=List->head;
        List->head=node;
    }
    else{
        nodes *temp=SearSeque(List,n-1);
        if(temp==NULL){
            cout<<"error"<<endl;
        }
        else{
            node->next=temp->next;
            temp->next=node;
        }
    }
}

前插法实现插入,把需要插入的结点插入到第n个位置之前,用到了前面的按序号查找函数。当n=1时,即将结点插入到第一个位置,查找函数返回的是head的地址,head指向的是第一个结点 ,而不是前一个结点的地址,所以要特殊操作一下。

后插法

//后插法插入,插入到第n位后
void InsertListII(Lists *List,int n,datatype x){
    nodes *node=(nodes*)malloc(sizeof(nodes));
    node->data=x;
    if(n==0){
        node->next=List->head;
        List->head=node;
    }
    else{
        nodes *temp=SearSeque(List,n);
        if(temp==NULL){
            cout<<"error"<<endl;
        }
        else{
            node->next=temp->next;
            temp->next=node;
        }
    }
}

后插法,将需要插入的结点插入到第n个位置的后面,当n=0时,即结点插入到第一个位置,需要特殊操作一波。

删除

 按序号删除

//按序号删除数据元素
void DeleSeque(Lists *List,int n){
    nodes *temp=SearSeque(List,n);
    if(temp==NULL){
        cout<<"error"<<endl;
    }
    else{
        if(n==1){
            List->head=temp->next;
            free(temp);
        }
        else {
            nodes *pretemp=SearSeque(List,n-1);
            pretemp->next=temp->next;
            free(temp);
        }
    }
}

按序号删除。删除操作就是把前一个结点直接指向需要删除结点的下一个结点,释放需要删除结点。删除的结点位置可能非法,也有可能前一个结点的位置非法,我觉得在删除的位置不非法的情况下,前一个结点位置非法的可能只有第一个结点了,所以单独讨论了n=1的情况。记得释放空间啊!

按值删除

//将链表中所有数值为num的结点删除
void DeleValue(Lists *List,datatype num){
    if(SearValue(List,num)==NULL){
        cout<<"no such data to delete!"<<endl;
    }
    else{
        nodes *pretemp=List->head;
        while(pretemp!=NULL&&pretemp->data==num){
            List->head=pretemp->next;
            free(pretemp);
            pretemp=List->head;
        }
        while(pretemp!=NULL&&pretemp->next!=NULL){
            nodes *temp=pretemp->next;
            if(temp->data==num){
                pretemp->next=temp->next;
                free(temp);
            }
            else {
                pretemp=pretemp->next;
            }
        }
    }
}

按值删除,删除了链表里所有值为num的结点。pretemp是当前结点,temp是它的下一个结点,看temp的值是否为num,是则删除,pretemp初始化指向第一个结点,因此可能会漏掉第一个结点,因此进行第一个while,将head更新到第一个不是num的结点处。注意第二个while的条件。。。因为下面用到了pretemp->next,所以pretemp不能是空指针,因为用到了temp->data,所以pretemp->next也不能是空指针。

计算链表长度

//输出链表长度
int length(Lists *List){
    nodes *temp=List->head;
    int len=0;
    while(temp!=NULL){
        len++;
        temp=temp->next;
    }
    return len;
}

打印链表

//打印链表
void print(Lists *List){
    nodes *temp=List->head;
    if(temp==NULL){
        cout<<"链式表为空!"<<endl;
    }
    else {
        cout<<"链式表的数据元素为 :"<<endl;
        while(temp!=NULL){
            cout<<temp->data<<" ";
            temp=temp->next;
        }
        cout<<endl;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值