C/C++ 链表详解

一、链表的删除、查找、插入等操作

前言: 该文章内容的第一大块是单独功能的讲述,比如链表的插入,删除,查找等操作; 第二大块是整个链表的一个完整操作示例。这两个模块没有任何关联,以防误解

1、准备内容

友情提示: 以下代码可以按序拷贝到开发工具中(有时会遇到版本兼容性问题).
该部分内容主要是准备工作,在操作之前,我们总得创建一个链表不是,接下来直接贴上。
(1)头文件

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

(2)结构体 我们链表需要存储的数据

typedef struct Node
{
    char name[15];		//姓名
    int age;					//年龄
    struct Node *next;	//指向 下一个节点
}Person;

接下来我们就创建一个以Person为基础的链表,首先编写一个创建链接的函数。
(3)创建链表的函数

Person * creatList()
{
    Person *head = (Person*)malloc(sizeof(Person)); 	//分配空间
    strcpy(head->name, "TOP");
    head->age = 0;
    head->next = NULL ;
        
    Person *p = head;
    Person *s = NULL ;
    
    for (int i=0; i<3; i++) {
        s = (Person*)malloc(sizeof(Person));
        printf("输入姓名和年龄:\n");
        scanf("%s %d",s->name, &(s->age));
        s->next = NULL;
        
        p->next = s;
        p = s;
    }    
    return head;
}

紧接着我们再编写一个打印链表的函数,这样在视觉上就能直接看出来链表有没有问题,岂不是很悠哉。
(4)打印链表的函数

void show(Person *head){
    Person *p = head;
    while (p != NULL ) {
        printf("name is %s, age is %d \n",p->name, p->age);
        p = p->next;
    }
    printf("==================================== \n");
}

基本工作处理完了,下面我们就要真刀真枪的走一遭了。

2、操作实现

(1)创建链表 在main函数中创建一个链表head1,我们之后的操作都是基于该链表。

Person *head1 = (Person*)malloc(sizeof(Person));  
head1 = creatList();  //创建链表1
show(head1); //打印链表

此时,如果代码没有符号或语句的问题,应该都能输出正确的链表。下面就讲述不同的操作功能。
(2)查找元素节点
我们用searchNode函数封装该方法,通过name来查找我们需要的节点:

Person* searchNode(Person *head, char *_name)
{
    Person *p = head;
    while (p != NULL) {
        if (strcmp(p->name, _name) == 0) {
            return p;
        }
        p = p->next;
    }
    return p;
}

之后,在main函数中调用该方法,参数“NAME”是你要查找的内容,可不能直接copy哈,比如你要查找的名字叫"Jack",就需要将参数NAME写成Jack

Person *search = searchNode(head1, (char*)"NAME");  
if (search != NULL)
{
    printf("had fond ,it's that:\n");
    printf("name is %s, age is %d \n",search->name, search->age);
}else{
    printf("not find \n");
}

(3)查找中间元素节点

Person * centerList(Person *head)
{
    Person *p = head;
    int cout = 0;
    while (p != NULL) {
        cout ++;
        p = p->next;
    }
    p = head;
    for (int i=0; i<(cout/2); i++) {
        p = p->next;
    }
    return p;
}

之后,我们在main函数中调用该方法,并输出:

 Person *center = centerList(head1); 
 printf("name is %s, age is %d \n",center->name, center->age);

(4)插入元素节点到指定位置
我们用insertNode函数封装该方法,下述代码中的 strcmp(p->name, “NAME”) 中的“NAME”,就是你要指定的位置。

void insertNode(Person *head)
{
    Person *p = head;
    while (p != NULL) {
        if (strcmp(p->name, "NAME") == 0) {
            Person *s = (Person*)malloc(sizeof(Person));
            printf("输入新节点信息:\n");
            scanf("%s%d",s->name, &(s->age));
            
            s->next = p->next;
            p->next = s;
        }
        p = p->next;
    }    
}

之后,在main函数中调用该方法:

insertNode(head1);
show(head1);  //打印一下链表,看看我们是否插入成功

(5)删除指定元素节点
我们用deleteNode函数封装该方法

Person* deleteNode(Person *head, char *_name)
{
    Person *p = head;
    Person *s = head->next;
    if (strcmp(p->name, _name) == 0) {
        head = head->next;
        free(p);
        p = NULL;
        return head;
    }
    while (s != NULL) {
        if (strcmp(s->name, _name) == 0) {
            p->next = s->next;
            free(s);
            s = NULL;
            return head;
        }
        p = s;
        s = s->next;
    }
    return head;
}

mian函数中直接调用, 参数NAME是你要删除的元素:

head1 = deleteNode(head1, (char*)"NAME");
show(head1);  //打印一下,看看成功了没有

(6)判断链表是否有环 定义两个指针,往同一个方向移动,一个移动速度快,一个移动速度慢(比如第一个指针每次移动一个节点,第二个指针每次移动两个节点)。如果链表有环,则两个指针会在某一节点相遇。

void annularList(Person *head)
{
    Person *p = head;  //慢速移动
    Person *s = head->next;   //快速移动
    
    while (s) {
        if (s == p)
        {
            printf("此链表有环\n");
            return;
        }
        else
        {
            s = s->next;
            if (!s) {
                printf("此链表没有环\n");
                return;
            }
            else
            {
                s = s->next;
                p = p->next;
            }
        }
    }
}

只需要在main函数中调用一下就行:

annularList(head1)

(7) 删除整个链表

void deletaAll(Person *head)
{
    Person *p = head;
    Person *s = p->next;
    while (s != NULL) {
        free(p);
        p = s;
        s = s->next;
    }
    free(p);
    p = NULL;
    head = NULL;        
}

main中调用一下就好了,参数记得传head1

好了,第一部分单独功能的描述已经完毕了。接下来,我们再大干一场。自古讲究和为贵,我们就融合两个链表,让它们成为一家。

二、 合并成有序链表

前言: 该部分和第一大块没有关联,请不要误解。
说明: 已知两个有序链表,自定义函数把这两个链表合并成一个依然有序的链表。
注意: 以下代码,可以按序全部拷贝到开发工具中(有时会遇到版本兼容性问题)。
1、引入头文件必不可少

#include<iostream>
using namespace std;

2、我们先定义一个 NODE 结构体,包括数据 和 指向下一个节点的指针。

typedef struct Node{
    int data;
    struct Node *next;    
}NODE;

3、准备工作结束了,我们需要先写一个创建链表的函数(在main函数中调用,样式在第5条)。

NODE* creadList(NODE *head){
    NODE *p1 = NULL;  //新节点指针
    NODE *p2 = NULL;  //动态指针
    head = p2 = p1 = (NODE*)malloc(sizeof(NODE));
    cout<<"请输入有序的整数,以0为结束标志:"<<endl;
    cin>> p1->data;
    for (; p1->data!=0; ) {
        p2 = p1;
        p1 = (NODE*)malloc(sizeof(NODE));
        cout<<"继续输入,直到输入0结束:"<<endl;
        cin>> p1->data;
        p2->next = p1;        
    }
    p2->next = NULL;
    return head;
};

4、当然,创建链表之后,我们总要输出一下,看看自己创建的链表是否合法。
再编写一个打印链表的函数(在main函数中调用,样式在第5条)。

void printList(NODE *head){
    NODE *p = NULL;
    p = head;
    if (head == NULL) {
        cout<<"空表"<<endl;
    }else{
        cout<<"链表元素是:"<<endl;
        for (;p!=NULL ; p=p->next) {
            cout<<p->data<<", ";
        }
        cout<<endl;
    }
    //为了便于区分每个链表的内容,我们输出分隔符号
    cout<<"==============================="<<endl;
}

5、好了,我们在main函数中调试一下,看看我们创建的链表能否正常执行。

int main(int argc, const char *argv[]){
    NODE* head1 = NULL;
    NODE* _head1 = creadList(head1);   //创建链表1
    printList(_head1);
}

可以发现,咱们的链表已经成功了,这很好。
6、接下来就是激动人心的时刻了,合并两个链表的方法 我们直接奉上。这段逻辑部分乍一看可能有些迷糊。如果你理解起来有些困难,可以拿笔在纸上写出两个有序链表,然后按照代码步骤一步一步画出来操作结果,这样就很容易理解了,其实还是很简单的。

NODE * unionList(NODE* head1, NODE* head2){
  
    if (head1 == NULL){
        return head2;
    }else if (head2 == NULL){
        return head1;
    }
    
    NODE *newHead = (NODE*)malloc(sizeof(NODE));
    if(head1->data <= head2->data){
        newHead = head1;
        head1 = head1->next;
    }else{
        newHead = head2;
        head2 = head2->next;
    }
    NODE *p = newHead;
    
    while (head1 != NULL && head2 != NULL) {
        if (head1->data <= head2->data) {
            p->next = head1;
            p = head1;
            head1 = head1->next;
        }else{
            p->next = head2;
            p = head2;
            head2 = head2->next;
        }
    }
    if (head1 == NULL) {
        p->next = head2;
        return newHead;
       
    }else if(head2 == NULL){
        p->next = head1;
        return newHead;
    }
    return newHead;
}

7、最后,我们完善main函数。为了预防初学者迷糊,我们将全部的main函数代码贴上。执行代码之后,按照提示输入链表数据,我们就可以将两个链表合并成一个有序链表了。

int main(int argc, const char *argv[]){
    NODE* head1 = NULL;
    NODE* _head1 = creadList(head1);   //创建链表1
    printList(_head1);
    
    NODE* head2 = NULL;    //创建链表2
    NODE* _head2 = creadList(head2);
    printList(_head2);
    
    NODE* _head = unionList(_head1, _head2); //合并 并 排序
    printList(_head);
   
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值