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;
}
相关推荐
whitelbwwww2 小时前
Pytorch--张量
开发语言·pytorch·python
2301_764441332 小时前
基于python与Streamlit构建的卫星数据多维可视化分析
开发语言·python·信息可视化
say_fall2 小时前
新手避坑指南:C++ 引用、内联函数与 nullptr 全解析
android·开发语言·c++
郝学胜-神的一滴2 小时前
深入浅出:理解OpenGL的标准化设备坐标(NDC)
开发语言·程序人生·图形渲染
中文很快乐2 小时前
java后端好习惯---新手养成记
java·开发语言·开发好习惯·踩坑日志·新手养成
风华同学2 小时前
【系统移植篇】系统烧写
java·开发语言·前端
by__csdn2 小时前
JavaScript性能优化实战:异步与延迟加载全方位攻略
开发语言·前端·javascript·vue.js·react.js·typescript·ecmascript
阿里嘎多学长2 小时前
2025-12-11 GitHub 热点项目精选
开发语言·程序员·github·代码托管
良木生香2 小时前
【数据结构-初阶】详解线性表(2)---单链表
c语言·数据结构·算法