c语言实现顺序表和链表(利用了c++的引用)

一:顺序表的插入和删除

顺序表是使用数组来实现的,同时还需要有一个提前定义好的长度(因为在c语言中数组定义时就要给定长度)。

顺序表插入的思路:

需要将数组插入的位置起,每一个元素后退一格,数组长度+1

顺序表删除的思路:

需要从删除的位置之后,每一个元素前进一格,顺序表长度-1

代码:

cpp 复制代码
#include <stdio.h>

#define MaxSize 50//数组存储最大的值

typedef int Eletype;//将int类型重命名为Eletype
typedef struct {
    Eletype data[MaxSize]; //顺序表存储数据的地方
    Eletype length;//顺序表实际存储数据的长度
}SqList;

bool addList(Eletype data,SqList &list,int i) {
    if (i<1 || i > list.length+1) {  //判断插入的位置合不合法,插入是可以插入到顺序表实际大小的后一个位置
        return false;
    }
    if (list.length == MaxSize) {   //当顺序表实际存储的数据数量和最大值一样时返回错误
        return false;
    }
    for (int j=list.length;j>i-1;j--) {  //从最后一个元素开始遍历,到需要插入元素的位置截至
        list.data[j] = list.data[j-1];   //将前面一个位置的元素值赋值给后一个元素
    }
    list.data[i-1] = data;   //最后将需要插入元素的值赋值给插入位置下标的前一个位置(数组下标是从0开始的)
    list.length++;    //插入元素之后顺序表的大小+1
    return true;
}

bool deleteList(SqList &list,int i){
    if (i<1 || i>list.length){ //删除只能删除顺序表里面有元素的位置
        return false;
    }
    if (list.length < 1){   //当顺序表里面没有元素时不可以删除
        return false;
    }
    for (int j = i-1; j < list.length-1; j++) {   //从需要删除元素位置的前一个下标开始,到顺序表末尾结束
        list.data[j] = list.data[j+1]; //将顺序表中后一个元素的值赋值给前一个元素(相当于覆盖删除)
    }
    list.length--; //删除元素之后,顺序表的大小-1
    return true;
}

bool selectList(Eletype data, SqList list){
    for (int i=0;i < list.length;i++){    //遍历顺序表
        if (list.data[i] == data){   //如果要查询的值和顺序表中的数据一样就返回true
            return true;
        }
    }
    return false;
}

int main() {
    //初始化顺序表
    SqList list;
    list.data[0] = 4;
    list.data[1] = 23;
    list.data[2] = 6;
    list.length=3;
    bool addRet = addList( 50,list,4);   //输入需要插入的元素,哪一个顺序表,插入的位置
    if (addRet) {
        printf("insert success\n");   //插入成功打印
        for (int i=0;i<list.length;i++) {
            printf("%d ",list.data[i]);   //循环打印出顺序表里面的数据
        }
        printf("\n");
    }else {
        printf("insert wrong");   //插入失败打印
    }
    printf("-----------\n");
    bool deleteRet = deleteList(list,4);
    if (deleteRet) {
        printf("delete success\n");   //删除成功打印
        for (int i=0;i<list.length;i++) {
            printf("%d ",list.data[i]);   //循环打印出顺序表里面的数据
        }
        printf("\n");
    }else {
        printf("delete wrong");   //删除失败打印
    }
    printf("-----------\n");
    bool selectRet = selectList(4,list);
    for (int i=0;i<list.length;i++) {
        printf("%d ",list.data[i]);   //循环打印出顺序表里面的数据
    }
    printf("\n");
    if (selectRet) {
        printf("select success\n");   //查询成功打印
        printf("\n");
    }else {
        printf("select wrong");   //查询失败打印
    }
    return 0;
}

二:链表的插入,删除,和查询

链表的存储在逻辑上是连续的,但是物理上(实际存储)是不连续的

建立链表的思路:

头插法:

建立完头指针之后建立的结点,通过头插法插入到链表中;每次插入时让头指针next指向结点的地址赋值给新结点next指向的位置;再将头指针next指向新的结点

尾插法:

建立完头指针之后建立的结点,通过尾插法插入到链表中,需要定义一个尾指针,每次插入之后尾指针指向最后一个结点用来保存最后一个结点的位置;将tai尾指针的next指向的位置指向新的结点,然后更新tail尾指针为新结点的位置,最后将新结点的next指向的地址置为NULL

具体实现代码:

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>

typedef int ElemType;
typedef struct Lode{
    ElemType data;
    struct Lode* next;
}Lode,*LinkList;

void head_insert_list(LinkList &l){
    l = (LinkList)malloc(sizeof(Lode));
    l->next = NULL;
    Lode *s;
    ElemType x;
    scanf("%d",&x);
    while (x != 9999){
        s = (LinkList)malloc(sizeof(Lode));
        s->data = x;
        s->next = l->next;
        l->next = s;
        scanf("%d",&x);
    }
}

void tail_insert_list(LinkList &l){
    l = (LinkList)malloc(sizeof(Lode));
    l->next =NULL;
    ElemType x;
    Lode *s;
    Lode *p = l;
    scanf("%d",&x);
    while (x!=9999){
        s = (LinkList)malloc(sizeof(Lode));
        s->data = x;
        p->next = s;
        p = s;
        scanf("%d",&x);
    }
    s->next=NULL;
}

void PrintList(LinkList L){
    L=L->next;
    while(L!=NULL)
    {
        printf("%d",L->data);//打印当前结点数据
        L=L->next;//指向下一个结点
        if(L!=NULL)
        {
            printf(" ");
        }
    }
    printf("\n");
}

int main() {
    LinkList l;
    head_insert_list(l);
    PrintList(l);
    tail_insert_list(l);
    PrintList(l);
    return 0;
}

链表的查询和删除:

查询思路:

(1)通过值查询

遍历链表,判断结束条件为结点不为NULL,判断结点的数据域是否和查询的值相等

(2)通过下标查询

额外定义一个伪下标,判断结束条件为(伪下标)<(查找的下标)和结点不为NULL,判断结点的数据域是否和查询的值相等

插入思路:

获取到插入位置前一个结点,将这个的next指向的地址赋值给插入结点的next域,最后将插入位置前一个结点指向插入结点的位置

删除思路:

遍历链表,找到删除位置和删除位置前一个结点,将删除位置的next地址赋值给前一个位置的next地址,然后释放删除位置的指针,最后将删除的结点置为NULL防止野指针

代码:

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>

typedef int ElemType;
typedef struct Lode{
    ElemType data;
    struct Lode* next;
}Lode,*LinkList;

void tail_insert_list(LinkList &l){
    l = (LinkList)malloc(sizeof(Lode));
    l->next =NULL;
    ElemType x;
    Lode *s;
    Lode *p = l;
    scanf("%d",&x);
    while (x!=9999){
        s = (LinkList)malloc(sizeof(Lode));
        s->data = x;
        p->next = s;
        p = s;
        scanf("%d",&x);
    }
    s->next=NULL;
}

LinkList GetElem(LinkList L,int searchI){    //根据下标查找值
    int i  = 0;           //用来和给定的下标对比,判断循环的结束条件
    if (searchI<0){       //检验给定下标的合法性
        return NULL;
    }
    while (L && i < searchI){   //这里注意是判断L为不为NULL不是L的next(会影响越界的searchI)
        L = L->next;            //先进行结点的移动,在对下标进行++
        i++;
    }
    return L;                   //循环结束之后停在的位置就是需要寻找
}

LinkList LocateElem(LinkList L,ElemType data){   //根据值查找值
    while (L){                                   //循环结束条件
        L=L->next;                               //遍历链表
        if (L->data == data){                    //如果值相等就返回此时的L
            return L;
        }
    }
    return NULL;       //循环结束说明没有找到,返回NULL
}

void insert_list(LinkList &L,ElemType data,int i){
    LinkList x = GetElem(L,i-1);  //查找需要插入位置前一个位置结点
    if (NULL == x){      //判断查询到的结点是否为空
        return;
    }
    LinkList s = (LinkList)malloc(sizeof(Lode)); //申请空间存放插入的结点
    s->next = x->next;     //将前一个结点记录的地址赋值给插入的结点
    x->next = s;           //将插入结点的地址连接到前一个结点
    s->data = data;        //赋值插入的值
}


void delete_list(LinkList &l,int deleteI){
    LinkList node = GetElem(l,deleteI-1);
    if (NULL == node){
        return;
    }
    LinkList deleteNode = node->next;
    if (NULL == deleteNode){
        return;
    }
    node->next = deleteNode->next;
    free(deleteNode);
    deleteNode = NULL;
}

void PrintList(LinkList L)
{
    L = L->next;
    while (L != NULL)
    {
        printf("%3d", L->data);//打印当前结点数据
        L = L->next;//指向下一个结点
    }
    printf("\n");
}

int main() {
    LinkList l;
    tail_insert_list(l);
    LinkList res = GetElem(l,1);
    printf("%d\n",res->data);
    insert_list(l,99,1);
    PrintList(l);
    delete_list(l,2);
    PrintList(l);
    return 0;
}
相关推荐
Scott9999HH7 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
码智社8 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海8 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖9 小时前
JDK 26 新特性详解
java·开发语言
马优晨10 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
人邮异步社区12 小时前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大12 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai13 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
এ慕ོ冬℘゜13 小时前
前端基础:什么是时间戳?JS获取时间戳三种方法与实战用途
开发语言·前端·javascript
执明wa13 小时前
LayoutInflater详解: XML是如何变成View的?
android·xml·开发语言·android studio