算法基础5 —— 线性表(链表的建立、输出、查找、插入、删除等操作)

线性表
  • 定义:线性表是最基本的一种数据结构,是数据结构的一种,一个线性表是n个具有相同特性的数据元素的有限序列。
  • 线性表中除了首元素和尾元素之外,每一个元素都有唯一的前驱和唯一的后续
  • 线性表包括顺序表链表,其中,可以将顺序表理解为数组
  • 链表:链表由各结点组成,每个结点至少包括数据域和指针域。
    在这里插入图片描述
    在上图中的链表里,head 为头结点(一般不存放数据),5所在结点为尾结点且其指针域为NULL

在这里插入图片描述

物理与逻辑
  • 物理上连续指的是数据元素在计算机内存中的地址是连续的
  • 逻辑上连续指的是人们想象中的元素相邻
链表的定义

1、首先,定义一个节点

struct node//定义结点类型
{
    int data;//数据域,存放数据
    struct node *next;//指针域:该指针指向下一个node结点的地址,故其类型为struct node
};

在这里插入图片描述
2、结点类型定义完成之后需要定义一个结点变量并且给它申请空间

struct node *p;//定义结点变量p(指针)
p=new node;//动态申请空间(使指针指向一个地址)
链表的创建以及输出代码
#include <iostream>
#include <cstdio>

using namespace std;

struct node//定义链表结点类型
{
    int data;//数据域,存放数据
    struct node *next;//指针域:该指针指向下一个node结点的地址,故其类型为struct node
};
typedef struct node * Node;//struct node *  = Node

void create(Node &head)
//创建函数
//不加&是复制了一个副本,creat函数运行完释放,加&是对同一片空间进行操作(知识点:值传递与引用)
{
    Node r,p;
    int x;
    cin >> x;
    
    if (head == NULL) head = new node;//如果当前head为空(头指针空),就为其申请一个结点空间;注意是node而不是Node
    
    r = head;//head和r指针指向同一个结点
    
    while (x != -1)//创建链表,以-1结束
    {
        p = new node;
        p -> data = x;
        p -> next = NULL;
        r -> next = p;
        r = p;
        
        cin >> x;
    }
}

void output(Node head)//输出链表
{
    if (head == NULL)
    {
        cout << "the list is empty!" << endl;
        return;
    }
    
    Node p = head -> next;
    while (p != NULL)//p指针不为空
    {
        cout << p -> data << " ";//输出当前结点的数据域
        p = p -> next;//指针后移
    }
}

int main()
{
    Node head = NULL;//head为头指针,注意要赋值为NULL,避免产生野指针,或者将creat函数中的head = new node写在这里
    create(head);//输入:2 3 4 -1
    output(head);//输出:2 3 4 
    return 0;
}
查找单链表中的某个元素x
bool find(Node head,int x)//查找单链表中是否含有x
{
    Node p = head -> next;
    while (p != NULL)
    {
        if (p -> data == x) return true;//找到x
        else p = p -> next;
    }
    return false;//表示未找到x
}
查找链表中的第i个元素并输出其数据域
void get(Node head,int i)
{
    Node p = head -> next;
    int j = 1;
    
    while ((p != NULL) && (j < i))
    {
        p = p -> next;
        j++;
    }
    
    if (p != NULL) cout << p -> data << endl;//找到结点
    else cout << "第i个结点不存在" << endl;//找不到结点:如链表中有4个元素,则无法找到第5个结点
}
find和get的测试代码
#include <iostream>
#include <cstdio>

using namespace std;

struct node//定义链表结点类型
{
    int data;//数据域
    struct node *next;//指针域
};
typedef struct node * Node;//struct node *  = Node

void create(Node &head)//创建函数
{
    Node r,p;
    int x;
    cin >> x;
    
    if (head == NULL) head = new node;
    
    r = head;//head和r指针指向同一个结点
    
    while (x != -1)//创建链表,以-1结束
    {
        p = new node;
        p -> data = x;
        p -> next = NULL;
        r -> next = p;
        r = p;
        
        cin >> x;
    }
}

void output(Node head)//输出链表
{
    if (head == NULL)
    {
        cout << "the list is empty!" << endl;
        return;
    }
    
    Node p = head -> next;
    while (p != NULL)//p指针不为空
    {
        cout << p -> data << " ";
        p = p -> next;
    }
}

bool find(Node head,int x)//查找单链表中是否含有x
{
    Node p = head -> next;
    while (p != NULL)
    {
        if (p -> data == x) return true;//找到x
        else p = p -> next;
    }
    return false;//表示未找到x
}

void get(Node head,int i)//寻找链表中的第i个结点并输出其数据域
{
    Node p = head -> next;
    int j = 1;
    
    while ((p != NULL) && (j < i))
    {
        p = p -> next;
        j++;
    }
    
    if (p != NULL) cout << p -> data << endl;//找到结点
    else cout << "第i个结点不存在" << endl;//找不到结点:如链表中有4个元素,则无法找到第5个结点
}

int main()
{
    Node head = NULL;//赋值为NULL,避免产生野指针    
    create(head);
    output(head);
    cout << endl;

    if(find(head,3)) cout << "Yes!" << endl;
    get(head,4);
    return 0;
}
链表的插入操作

在给定位置插入一个新结点

① s->next = p->next;
② p->next=s;

注:①②两句代码不可交换顺序,否则会发生断链。如下图,将结点4插入到结点3和结点5之间,如果先执行p->next=s;则结点3指向结点5的指针会断开,从而找不到结点5,无法完成插入操作。
在这里插入图片描述

void insert(Node &head,int i,int x)//在第i个位置插入元素x
{
    Node s = new node;//新建一个结点,用指针s指向
    s -> data = x;
    
    if (i == 1)//在第一个位置插入元素时需要特判(请尝试不写该句会怎么样)
    {
        Node p = head;
        s -> next = p -> next;//插入
        p -> next = s;
    }
    else
    {
        Node p = get(head,i - 1);//在第二个位置插入结点,需要先找到第一个结点的位置
        s -> next = p -> next;//插入
        p -> next = s;
    }
}
链表的删除操作
p -> next = p -> next -> next;

在这里插入图片描述

void delNode(Node &head,int i)//删除第i个位置的结点(注意&符号)
{
    if (i == 1)//此处要特判 
    {
        Node p = head;
        p -> next = p -> next -> next;//删除操作
    }
    else 
    {
        Node p = get(head,i - 1);//删除第i个位置的结点,需要先找到第i - 1个结点的位置(直接调用get函数更简单)
        p -> next = p -> next -> next;
    }
}
插入和删除的测试代码
#include <iostream>
#include <cstdio>

using namespace std;

struct node//定义链表结点类型
{
    int data;//数据域
    struct node *next;//指针域
};
typedef struct node * Node;//struct node *  = Node

void create(Node &head)//创建函数
{
    Node r,p;
    int x;
    cin >> x;
    
    if (head == NULL) head = new node;
    
    r = head;//head和r指针指向同一个结点
    
    while (x != -1)//创建链表,以-1结束
    {
        p = new node;
        p -> data = x;
        p -> next = NULL;
        r -> next = p;
        r = p;
        
        cin >> x;
    }
}

void output(Node head)//输出链表
{
    if (head == NULL)
    {
        cout << "the list is empty!" << endl;
        return;
    }
    
    Node p = head -> next;
    while (p != NULL)//p指针不为空
    {
        cout << p -> data << " ";
        p = p -> next;
    }
}

Node get(Node head,int i)//寻找链表中的第i个结点,返回值为该结点的位置
{
    Node p = head -> next;
    int j = 1;
    
    while ((p != NULL) && (j < i))
    {
        p = p -> next;
        j++;
    }
    
    if (p != NULL) return p;
    else return NULL;
}

void insert(Node &head,int i,int x)//在第i个位置插入元素x
{
    Node s = new node;//新建一个结点,用指针s指向
    s -> data = x;
    
    if (i == 1)//在第一个位置插入元素时需要特判(请尝试不写该句会怎么样)
    {
        Node p = head;
        s -> next = p -> next;//插入
        p -> next = s;
    }
    else
    {
        Node p = get(head,i - 1);//在第二个位置插入结点,需要先找到第一个结点的位置
        s -> next = p -> next;//插入
        p -> next = s;
    }
}

void delNode(Node &head,int i)//删除第i个位置的结点(注意&符号)
{
    if (i == 1)//(请各位试一下如果此处不特判,会怎么样)
    {
        Node p = head;
        p -> next = p -> next -> next;//删除操作
    }
    else 
    {
        Node p = get(head,i - 1);//删除第i个位置的结点,需要先找到第i - 1个结点的位置(直接调用get函数更简单)
        p -> next = p -> next -> next;
    }
}

int main()
{
    Node head = NULL;   
    create(head);//1 3 4 
    output(head);//1 3 4 
    cout << endl;

    insert(head,1,2);//测试插入操作
    output(head);//2 1 3 4 
    cout << endl;
    
    delNode(head,4);//测试删除操作
    output(head);//2 1 3
    return 0;
}
求链表的实际长度(不包含头结点)
void len(Node head)
{
    int length = 0;
    Node p = head -> next;
    
    while (p != NULL)
    {
        length++;
        p = p -> next;
    }
    cout << length;
}
链表长度的测试代码
#include <iostream>
#include <cstdio>

using namespace std;

struct node//定义链表结点类型
{
    int data;//数据域
    struct node *next;//指针域
};
typedef struct node * Node;//struct node *  = Node

void create(Node &head)//创建函数
{
    Node r,p;
    int x;
    cin >> x;
    
    if (head == NULL) head = new node;
    
    r = head;//head和r指针指向同一个结点
    
    while (x != -1)//创建链表,以-1结束
    {
        p = new node;
        p -> data = x;
        p -> next = NULL;
        r -> next = p;
        r = p;
        
        cin >> x;
    }
}

void output(Node head)//输出链表
{
    if (head == NULL)
    {
        cout << "the list is empty!" << endl;
        return;
    }
    
    Node p = head -> next;
    while (p != NULL)//p指针不为空
    {
        cout << p -> data << " ";
        p = p -> next;
    }
}

Node get(Node head,int i)//寻找链表中的第i个结点,返回值为该结点的位置
{
    Node p = head -> next;
    int j = 1;
    
    while ((p != NULL) && (j < i))
    {
        p = p -> next;
        j++;
    }
    
    if (p != NULL) return p;
    else return NULL;
}

void insert(Node &head,int i,int x)//在第i个位置插入元素x
{
    Node s = new node;//新建一个结点,用指针s指向
    s -> data = x;
    
    if (i == 1)//在第一个位置插入元素时需要特判(请尝试不写该句会怎么样)
    {
        Node p = head;
        s -> next = p -> next;//插入
        p -> next = s;
    }
    else
    {
        Node p = get(head,i - 1);//在第二个位置插入结点,需要先找到第一个结点的位置
        s -> next = p -> next;//插入
        p -> next = s;
    }
}

void delNode(Node &head,int i)//删除第i个位置的结点(注意&符号)
{
    if (i == 1)//(请各位试一下如果此处不特判,会怎么样)
    {
        Node p = head;
        p -> next = p -> next -> next;//删除操作
    }
    else 
    {
        Node p = get(head,i - 1);//删除第i个位置的结点,需要先找到第i - 1个结点的位置(直接调用get函数更简单)
        p -> next = p -> next -> next;
    }
}

void len(Node head)
{
    int length = 0;
    Node p = head -> next;
    
    while (p != NULL)
    {
        length++;
        p = p -> next;
    }
    cout << length;
}

int main()
{
    Node head = NULL;   
    create(head);//1 3 4 
    output(head);//1 3 4 
    cout << endl;
    len(head);//3
    cout << endl << endl;

    insert(head,1,2);//测试插入操作
    output(head);//2 1 3 4
    cout << endl;
    len(head);//4
    cout << endl << endl;
    
    delNode(head,4);//测试删除操作
    output(head);//2 1 3
    cout << endl;
    len(head);//3
    return 0;
}
  • 5
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
链式线性表是由一系列结点组成的链表,每个结点都包含一个数据元素和一个指针域指向下一个结点。链表的头结点没有数据元素,只有一个指针域指向第一个真正的结点。 链式线性表建立可以通过不断地插入新结点来实现。具体步骤如下: 1. 创建头结点,将其指针域设为 NULL。 2. 输入第一个数据元素,创建一个新结点并将数据元素存储在其中,同时让头结点的指针域指向该结点。 3. 重复以上步骤,直到所有数据元素都被插入链表中。 链式线性表插入操作可以分为两种情况: 1. 在链表的某个位置插入一个新结点。 2. 在链表的末尾插入一个新结点。 对于情况一,需要先找到要插入的位置,然后创建新结点并将其插入链表中。具体步骤如下: 1. 找到要插入的位置,即该位置的前一个结点。 2. 创建新结点并将数据元素存储在其中。 3. 将新结点的指针域指向原位置的下一个结点。 4. 将原位置的前一个结点的指针域指向新结点。 对于情况二,只需要创建一个新结点并将其插入链表的末尾即可。 链式线性表删除操作也可以分为两种情况: 1. 删除链表的某个位置的结点。 2. 删除链表的末尾结点。 对于情况一,需要先找到要删除的结点,然后将其从链表删除。具体步骤如下: 1. 找到要删除的结点,即该位置的前一个结点。 2. 将前一个结点的指针域指向要删除结点的下一个结点。 3. 释放要删除的结点的内存空间。 对于情况二,需要先找到链表的末尾结点,然后将其从链表删除。 链式线性表的合并操作可以将两个链表合并为一个链表。具体步骤如下: 1. 找到第一个链表的末尾结点。 2. 将第一个链表的末尾结点的指针域指向第二个链表的头结点。 3. 释放第二个链表的头结点的内存空间。 4. 返回第一个链表的头结点。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值