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;
}
相关推荐
yaoxin52112315 分钟前
279. Java Stream API - Stream 拼接的两种方式:concat() vs flatMap()
java·开发语言
@小码农17 分钟前
202512 电子学会 Scratch图形化编程等级考试三级真题(附答案)
服务器·开发语言·数据结构·数据库·算法
Cosmoshhhyyy32 分钟前
《Effective Java》解读第29条:优先考虑泛型
java·开发语言
一路往蓝-Anbo34 分钟前
C语言从句柄到对象 (六) —— 继承与 HAL:父类指针访问子类数据
c语言·开发语言·stm32·嵌入式硬件·物联网
北冥有一鲲37 分钟前
A2A协议与LangChain.js实战:构建微型软件工厂
开发语言·javascript·langchain
Chen不旧44 分钟前
java基于reentrantlock/condition/queue实现阻塞队列
java·开发语言·signal·reentrantlock·await·condition
nuo5342021 小时前
Nuo-Math-Compiler
c语言·编辑器
laplace01231 小时前
Part 3:模型调用、记忆管理与工具调用流程(LangChain 1.0)笔记(Markdown)
开发语言·人工智能·笔记·python·langchain·prompt
风送雨1 小时前
八周Python强化计划(七)
开发语言·python
ππ很开心6661 小时前
DAY 32 函数专题2:装饰器
开发语言·python