C语言实现的线性表

本文详细介绍了线性表的概念、抽象数据类型描述以及顺序和链式存储的实现,包括顺序表的数组实现、链表的操作如插入、删除和查找,以及广义表、双链表、循环列表和多重链表等高级数据结构的应用。
摘要由CSDN通过智能技术生成

线性表

由同类型数据元素构成的有序线性序列的线性结构

  • 表中元素个数称为线性表的长度
  • 线性表没有元素时,称为空表
  • 表起始位置称表头,表结束位置称表尾

对于除空表外的任何表,我们说 A i + 1 A_{i+1} Ai+1后继 A i A_i Ai并称 A i − 1 A_{i-1} Ai1前驱 A i A_i Ai

线性表的抽象数据类型描述

线性表(List)
数据对象集:线性表是n个数据元素的有限序列
操作集
List MakeEmpty()初始化一个空线性列表L
ElementType FindKth(int k,List L)返回线性表L中第k个位置的元素
int Find(ElementType x,List L)返回线性表L中第一个与x相等的元素位置
void Insert(ElementType X,int k,List L)在线性表L中第k个位置插入元素X
void Delete(int K,List L)删除线性表L中第K个位置的元素
int Length(List L)返回线性表L的元素个数

线性表的顺序存储实现

利用数组的连续存储空间顺序存放线性表中的元素

typedef struct LNode *List;
struct LNode{
    ElemType Data[MAXSIZE];
    int Last;
};
struct LNode L;
List PtrL;

访问下标为i的元素:L.Data[i]或PtrL->Data[i]
线性表的长度:L.Last+1或PtrL->Last+1

主要操作实现

初始化(建立空的顺序表)

List MakeEmpty(){
    List PtrL;
    PtrL = (List)malloc(sizeof(struct LNode));
    PtrL->Last = -1;
    return PtrL;
}

查找(下标增序找到的第一个合适的元素)

int Find(ElemType X,List PtrL){
    int i = 0;
    while(i <= PtrL->Last && PtrL->Data[i] != X) i++;
    if(i > PtrL->Last) return -1;//没找到
    else return i;//找到了,返回下标
}

插入

void Insert(ElemType X, int i, List PtrL) {
    int j;
    if(PtrL->Last == MAXSIZE-1){//满了,不能插入
        printf("顺序表已满");
        return;
    }
    if(i < 1 || i > PtrL->Last+2){//检查插入位置的合法性
        printf("插入位置不合法");
        return;
    }
    for(j=PtrL->Last; j>=i-1; j--) PtrL->Data[j+1] = PtrL->Data[j];//将第i-1个元素到最后一个元素向后移动一个位置
    PtrL->Data[i-1] = X;//新元素插入
    PtrL->Last++;//Last仍指向最后元素
    return;
}

删除

void Delete(int i,List PtrL){
    int j;
    if(i<1 || i>PtrL->Last+1){//检查删除位置的合法性
        printf("不存在第%d个元素",i);
        return;
    }
    for(j=i; j<=PtrL->Last; j++) PtrL->Data[j-1] = PtrL->Data[j];//将第i个元素到最后一个元素向前移动一个位置
    PtrL->Last--;
    return;
}
线性表的顺序存储实现完整代码
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100

typedef int ElemType;
typedef struct LNode* List;
struct LNode {
    ElemType Data[MAXSIZE];
    int Last;
};

List PtrL;

int IsEmpty(List L);
List MakeEmpty();
void Insert(ElemType X, int i, List L);
int FindTheFirst(ElemType x, List L);
void Traverse(List L);
void Delete(int i, List L);
int Length(List L);

int main() {
    PtrL = MakeEmpty();
    if (PtrL == NULL) {
        printf("内存分配失败\n");
        return;
    }
    int choice, site;
    ElemType X;
    while (1) {
        printf("请选择你的操作:\n"
        "1.插入一个单元\n"
        "2.查找一个单元\n"
        "3.遍历已有顺序表\n"
        "4.删除一个单元\n"
        "5.查看表长\n"
        "6.删除这个顺序表\n");
        scanf("%d", &choice);
        switch (choice) {
        case 1:
            printf("插入的元素:");
            scanf("%d", &X);
            printf("想插入到的位置:");
            scanf("%d", &site);
            Insert(X, site, PtrL);
            break;
        case 2:
            if (IsEmpty(PtrL)) break;
            printf("要找什么?");
            scanf("%d", &X);
            FindTheFirst(X, PtrL) == 0 ? printf("没有该元素\n") : printf("在顺序标的第%d个\n", FindTheFirst(X, PtrL));
            break;
        case 3:
            if (IsEmpty(PtrL)) break;
            Traverse(PtrL);
            break;
        case 4:
            if (IsEmpty(PtrL)) break;
            printf("删第几个");
            scanf("%d", &site);
            Delete(site, PtrL);
            break;
        case 5:
            if (IsEmpty(PtrL)) break;
            printf("表长为%d\n", Length(PtrL));
            break;
        case 6:
            if (IsEmpty(PtrL)) ;
            else printf("已经删除,"); 
            printf("已经自动退出程序");
            free(PtrL);
            exit(0);
        }
        printf("\n");
    }
    return 0;
}

int IsEmpty(List L) {
    if (L == NULL || L->Last == -1) {
        printf("还没有表呢\n");
        return 1;
    }
    return 0;
}

List MakeEmpty() {
    List PtrL = (List)malloc(sizeof(struct LNode));
    if (PtrL != NULL) {
        PtrL->Last = -1;
    }
    return PtrL;
}

void Insert(ElemType X, int site, List L) {
    if (L->Last == MAXSIZE - 1) {
        printf("表已经满了\n");
        return;
    }
    else if (site < 1 || site > L->Last + 2) {
        printf("这地方插不了\n");
        return;
    }
    else {
        L->Last++;
        int sub_insert = L->Last + 1;
        while (sub_insert != L->Last) {
            L->Data[sub_insert] = L->Data[--sub_insert];
        }
        L->Data[sub_insert] = X;
        printf("已插入\n");
        return;
    }
}

int FindTheFirst(ElemType x, List L) {
    int index = 0;
    while (index <= L->Last && L->Data[index] != x) index++;
    if (index > L->Last) return 0;
    else return index + 1;
}

void Traverse(List L) {
    for (int sub_traverse = 0; sub_traverse <= L->Last; sub_traverse++) {
        printf("%d", L->Data[sub_traverse]);
        if (sub_traverse < L->Last) printf(" ");
    }
    return;
}

void Delete(int site, List L) {
    while (site <= L->Last + 1) {
        L->Data[site - 1] = L->Data[site++];
    }
    L->Last--;
    return;
}

int Length(List L) {
    return L->Last + 1;
}

线性表的链式存储实现

不要求逻辑上相邻的两个元素物理上也相邻,通过“链”建立起数据元素之间的逻辑关系

  • 插入删除不需要移动元素,只需修改指针
typedef struct LNode *List;
struct LNode{
    ElementType Data;
    List Next;
};
struct LNode L;
List PtrL;

主要操作实现

求表长

int Length(List PtrL){
    List p = PtrL;//p指向第一个节点
    int j = 0;
    while(p){
        p = p->Next;
        j++;//当前p指向的是第j个节点
    }
    return j;
}

查找
按照序号查找:FindKth

List FindKth(int K, List PtrL){
    List p = PtrL;
    int i = 1;
    while(p! = NULL && i<K){
        p = p->Next;
        i++;
    }
    if(i == K) return p;
    else return NULL;
}

按照值查找:Find

List Find(ElementType X, List PtrL){
    List p = PtrL;
    while(p != NULL && p->Data != X) p = p->Next;
= PtrL;
    return p;
}

插入

先构造一个新节点,用s指向
再找到链表的第i-1个节点,用p指向
然后修改指针,插入节点(p之后插入新节点是s)

操作实现

List Insert(ElementType X,int i,List PtrL){
    List s,p;
    if(i==1){//在表头插入
        s = (List)malloc(sizeof(struct LNode));
        s->Data = X;
        s->Next = PtrL;
        return s;
    }
    p = FindKth(i-1,PtrL);//找到第i-1个节点
    if(p == NULL){//第i-1个节点不存在
        printf("参数i错误");
        return NULL;
    }else{
        s = (List)malloc(sizeof(struct LNode));
        s->Data = X;
        s->Next = p->Next;
        p->Next = s;
        return PtrL;
    }
}

删除

找到链表的第i-1个结点,用p指向
再用指针s指向p的下一个节点
修改指针,删除s所指节点
释放s所占空间

操作实现

List Delete(int i, List PtrL){
    List p,s;
    if(i==1){//删除第一个节点
        s = PtrL;//s指向第一个节点
        if(Ptrl!= NULL)
        PtrL = PtrL->Next;
        else return NULL;
        free(s);
        return PtrL;
    }
    p = FindKth(i-1,PtrL);
    if(p == NULL){
        printf("第%d个元素不存在",i);
        return NULL;
    }else if(p->Next == NULL){
        printf("第%d个元素不存在",i);
        return NULL;
    }else{
        s = p->Next;
        p->Next = s->Next;
        free(s);
        return PtrL;
    }
}
链表实现的顺序表完整代码

一个包含学生信息(主要包括学号、姓名、班级和成绩等)的链表

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

typedef int ElemType;
typedef struct {
    char Stu_ID[10];
    char Stu_name[20];
    char Class_ID[10];
    int score;
}Student;
struct Node {
    Student Data;
    struct Node* Next;
};

typedef struct Node* LNode;
LNode List;//头结点

void Menu();
LNode Create_Student_List();
bool IsEmpty(LNode List);
void Show(LNode List);
void Find_By_Name(LNode List, const char* name);
bool Find_By_Position(LNode List, int position);
bool Insert_By_Position(LNode List, int position, Student stu);
bool Delete_By_Position(LNode List, int position, Student stu);
int Count(LNode List);
void DestroyList(LNode* List);

int main() {
    Student stu;
    char stu_name[20];
    int position, choice;
    printf("初始化一个学生信息链表\n");
    List = Create_Student_List();
    if (List == NULL) {
        printf("内存分配失败");
        return;
    }
    while (1) {
        Menu();
        scanf("%d", &choice);
        switch (choice) {
        case 1:
            if (IsEmpty(List)) break;
            Show(List);
            break;
        case 2:
            if (IsEmpty(List)) break;
            printf("\n请输入要查学生的姓名:");
            scanf("%s", stu_name);
            Find_By_Name(List, stu_name);
            break;
        case 3:
            if (IsEmpty(List)) break;
            printf("\n请输入要查学生的逻辑序号:");
            scanf("%d", &position);
            if (!Find_By_Position(List, position))
                printf("该逻辑序号不存在\n");
            break;
        case 4:
            printf("\n请输入一个新学生的插入位置(逻辑序号):");
            scanf("%d", &position);
            printf("\n请输入新学生的信息(学号,姓名,班级,成绩):");
            scanf("%s", stu.Stu_ID);
            scanf("%s", stu.Stu_name);
            scanf("%s", stu.Class_ID);
            scanf("%d", &stu.score);
            if (!Insert_By_Position(List, position, stu))
                printf("插入失败!");
            else
                printf("插入成功!");
            Show(List);
            break;
        case 5:
            if (IsEmpty(List)) break;
            printf("\n请输入要删除学生的位置(逻辑序号):");
            scanf("%d", &position);
            if (position < 1) printf("输入位置不合法");
            else if (!Delete_By_Position(List, position, stu))
                printf("删除失败!");
            else printf("删除成功!");
            Show(List);
            break;
        case 6:
            printf("\n学生表中学生的人数为:%d\n", Count(List));
            break;
        case 7:
            DestroyList(&List);
            exit(0);
        }
    }

    return 0;
}

void Menu() {
    printf("\n1: 显示学生信息\n");
    printf("2: 根据姓名进行查找\n");
    printf("3: 根据指定的位置输出相应的学生信息\n");
    printf("4: 插入一个学生\n");
    printf("5: 删除一个学生\n");
    printf("6: 统计表中学生个数\n");
    printf("7: 退出\n");
    printf("\n请选择:");
}

LNode Create_Student_List() {
    LNode List = (LNode)malloc(sizeof(struct Node));
    List->Next = NULL;
    return List;
}

bool IsEmpty(LNode List) {
    if (List->Next == NULL) {
        printf("还没有添加任何学生");
        return true;
    }
    return false;
}

void Show(LNode List) {
    LNode PtrL = List->Next;
    while (PtrL) {
        printf("%s %s %s %d\n", PtrL->Data.Stu_ID, PtrL->Data.Stu_name, PtrL->Data.Class_ID, PtrL->Data.score);
        PtrL = PtrL->Next;
    }
    return;
}

void Find_By_Name(LNode List, const char* name) {
    LNode PtrL = List->Next;
    while (strcmp(name, PtrL->Data.Stu_name) != 0 && PtrL->Next != NULL) {
        PtrL = PtrL->Next;
    }
    if (strcmp(name, PtrL->Data.Stu_name) == 0) {
        printf("找到了\n%s %s %s %d\n", PtrL->Data.Stu_ID, PtrL->Data.Stu_name, PtrL->Data.Class_ID, PtrL->Data.score);
        return;
    }
    else printf("没有该学生\n");
}

bool Find_By_Position(LNode List, int position) {
    int index = 1;
    LNode PtrL = List->Next;
    while (PtrL->Next != NULL && index < position) {
        PtrL = PtrL->Next;
        index++;
    }
    if (index != position) return false;
    else {
        printf("找到了\n%s %s %s %d\n", PtrL->Data.Stu_ID, PtrL->Data.Stu_name, PtrL->Data.Class_ID, PtrL->Data.score);
        return true;
    }
}

bool Insert_By_Position(LNode List, int position, Student stu) {
    int index = 1;
    LNode NewNode = Create_Student_List();
    NewNode->Data = stu;
    LNode PtrL = List;
    while (PtrL->Next != NULL && index < position) {
        PtrL = PtrL->Next;
        index++;
    }
    if (index != position) return false;
    else {
        NewNode->Next = PtrL->Next;
        PtrL->Next = NewNode;
        return true;
    }
}

bool Delete_By_Position(LNode List, int position, Student stu) {
    int index = 1;
    LNode PtrL = List->Next;
    while (PtrL->Next != NULL && index < position) {
        PtrL = PtrL->Next;
        index++;
    }
    if (index != position) return false;
    else {
        stu = PtrL->Next->Data;
        printf("删除学生:%s %s %s %d\n", stu.Stu_ID, stu.Stu_name, stu.Class_ID, stu.score);
        LNode j = PtrL->Next;
        PtrL->Next = PtrL->Next->Next;
        free(j);
        return true;
    }
}

int Count(LNode List) {
    int count = 0;
    LNode PtrL = List;
    while (PtrL->Next != NULL) {
        PtrL = PtrL->Next;
        count++;
    }
    return count;
}

void DestroyList(LNode* List) {
    LNode PtrL, temp;
    PtrL = *List;
    while (PtrL != NULL) {
        temp = PtrL->Next;
        free(PtrL);
        PtrL = temp;
    }
    *List = NULL;
}

广义表

广义表是线性表的推广
对于线性表而言,n个元素都是基本的单元素
广义表中,这些元素不仅可以是单元素也可以是另一个广义表

typedef struct GNode *GList;
struct GNode{
    int Tag;//标志域,0表示单元素,1表示广义表
    union{//子表指针域Sublist与单元数据域Data复用,及公用存储空间
        ElementType Data;
        GList SubList;
    }URegion;
    GList Next;//指向后继节点
};

广义表

双链表

其开销是一个附加的链,它增加了空间的需求,同时也使得插入和删除的开销增加了一倍,因为有更多的指针需要定位。另外,它简化了删除操作,因为你不再被迫使用一个指向前驱元的指针来访问一个关键字

双链表

循环列表

让最后的单元反过来指向第一个单元,它可以有表头,也可以没有(若有,则最后的单元就指向它),并且还可以是双向链表

循环链表

多重链表

链表中的结点可能同时隶属于多个链

  • 多重链表中的结点有多个指针域
  • 但包含两个指针域的链表并不一定是一个多重链表,比如双向链表就不是多重链表

树,图这样相对复杂的数据结构都可以采用多重链表方式存储

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值