C语言数据结构_期末复习(2)顺序表和链表

目录

一、线性表的特点

逻辑结构:

操作规则:

二、顺序表

顺序表与线性表的关系:

Length与Size:

判空与判满:

4.用C语言实现顺序表

1.构造存储结构

2.初始化 

3.插入数据

4.删除数据

5.判断顺序表是否为空

6.判断顺序表是否已满

5.练习题 

1.有序递增插入数据

2.有序递增删除数据

3.遍历打印顺序表

4.主函数

三、链表

链表的基本概念

逻辑结构:

存储方式:

结点:

单链表

1. 单链表的存储结构

2. 单链表的基本操作

关系:顺序表和链表是线性表的两种具体实现方式

线性表:

顺序表:

链表:

选择原则:

应用场景:

一、线性表的特点

  1. 逻辑结构

    • 具有线性结构,有表头(没有前驱)、有表尾(没有后继)。
    • 有且只有一个直接前驱和一个直接后继。
  2. 操作规则

    • 任意位置插入和删除数据。

二、顺序表

  1. 顺序表与线性表的关系

    顺序表是线性表的顺序存储结构。
  2. Length与Size

    • Length表示当前顺序表中的元素个数。
    • Size表示顺序表的总容量。
  3. 判空与判满

    • 顺序表为空:Length == 0
    • 顺序表已满:Length == Size

4.用C语言实现顺序表

1.构造存储结构
#define MAX_SIZE 8
typedef int DataType;

typedef struct {
    DataType data[MAX_SIZE];
    int length;
} SeqList;

2.初始化 
/* 初始化 */
void initSeqList(SeqList *list) {
    list->length = 0;
}
3.插入数据
/* 插入数据 */
void insert(SeqList *list, int index, DataType data) {
    if (list->length >= MAX_SIZE) {
        printf("顺序表已满,无法插入数据\n");
        return;
    }

    if (index < 0 || index > list->length) {
        printf("插入位置不合法\n");
        return;
    }

    for (int i = list->length; i > index; --i) {
        list->data[i] = list->data[i - 1];
    }

    list->data[index] = data;
    ++list->length;
}
4.删除数据
/* 删除数据 */
void delete(SeqList *list, int index) {
    if (index < 0 || index >= list->length) {
        printf("删除位置不合法\n");
        return;
    }

    for (int i = index; i < list->length - 1; ++i) {
        list->data[i] = list->data[i + 1];
    }

    --list->length;
}
5.判断顺序表是否为空
/* 判断顺序表是否为空 */
int isEmpty(SeqList *list) {
    return list->length == 0;
}
6.判断顺序表是否已满
/* 判断顺序表是否已满 */
int isFull(SeqList *list) {
    return list->length == MAX_SIZE;
}

5.练习题 

1.有序递增插入数据
/* 有序递增插入数据 */
void insertSorted(SeqList *list, DataType data) {
    int i = 0;
    
    while (i < list->length && data > list->data[i]) {
        ++i;
    }

    insert(list, i, data);
}
2.有序递增删除数据
/* 有序递增删除数据 */
void deleteSorted(SeqList *list, DataType data) {
    int i = 0;

    while (i < list->length && data != list->data[i]) {
        ++i;
    }

    if (i < list->length) {
        delete(list, i);
    } else {
        printf("数据 %d 不在顺序表中\n", data);
    }
}
3.遍历打印顺序表
/* 遍历打印顺序表 */
void printList(SeqList *list) {
    for (int i = 0; i < list->length; ++i) {
        printf("%d\t", list->data[i]);
    }
    printf("\n");
}
4.主函数
int main() {
    SeqList list;
    initSeqList(&list);

    int input;
    while (1) {
        printf("请输入正整数插入数据,负整数删除数据,0结束:");
        scanf("%d", &input);

        if (input == 0) {
            break;
        } else if (input > 0) {
            if (!isFull(&list)) {
                insertSorted(&list, input);
                printList(&list);
            } else {
                printf("顺序表已满,无法插入数据\n");
            }
        } else if (input < 0) {
            if (!isEmpty(&list)) {
                deleteSorted(&list, -input);
                printList(&list);
            } else {
                printf("顺序表为空,无法删除数据\n");
            }
        }
    }

    return 0;
}

三、链表

链表的基本概念

链表是一种基本的数据结构,与顺序表相比,链表具有以下特点:

  1. 逻辑结构
    • 仍然是线性结构,但没有表头和表尾的概念。
    • 通过指针将结点按照一定的逻辑次序连接起来。
  2. 存储方式
    • 采用动态存储方式,不需要预先分配存储空间。
  3. 结点
    • 链表中的每个元素称为结点(Node),每个结点包括数据域和指针域。
    • 数据域存储结点的数据。
    • 指针域存储指向下一个结点的指针。

单链表

1. 单链表的存储结构
typedef int DataType;

typedef struct Node {
    DataType data;
    struct Node *next;
} ListNode, *ListPtr;

2. 单链表的基本操作

初始化:

/* 初始化单链表 */
void initList(ListPtr *head) {
    *head = (ListPtr)malloc(sizeof(ListNode));
    if (*head == NULL) {
        printf("内存分配失败\n");
        exit(1);
    }

    (*head)->next = NULL;
}

插入结点:

/* 在位置pos后插入结点 */
void insertNode(ListPtr head, int pos, DataType data) {
    if (pos < 0) {
        printf("插入位置不合法\n");
        return;
    }

    ListPtr newNode = (ListPtr)malloc(sizeof(ListNode));
    if (newNode == NULL) {
        printf("内存分配失败\n");
        exit(1);
    }

    newNode->data = data;
    newNode->next = NULL;

    ListPtr p = head;
    for (int i = 0; i < pos && p != NULL; ++i) {
        p = p->next;
    }

    if (p == NULL) {
        printf("插入位置不合法\n");
        free(newNode);
        return;
    }

    newNode->next = p->next;
    p->next = newNode;
}

删除结点:

/* 删除位置pos的结点 */
void deleteNode(ListPtr head, int pos) {
    if (pos < 0) {
        printf("删除位置不合法\n");
        return;
    }

    ListPtr p = head;
    for (int i = 0; i < pos && p != NULL; ++i) {
        p = p->next;
    }

    if (p == NULL || p->next == NULL) {
        printf("删除位置不合法\n");
        return;
    }

    ListPtr temp = p->next;
    p->next = temp->next;
    free(temp);
}

遍历打印单链表:

/* 遍历打印单链表 */
void printList(ListPtr head) {
    ListPtr p = head->next;

    while (p != NULL) {
        printf("%d\t", p->data);
        p = p->next;
    }

    printf("\n");
}

主函数:

int main() {
    ListPtr list;
    initList(&list);

    int input;
    while (1) {
        printf("请输入正整数插入数据,负整数删除数据,0结束:");
        scanf("%d", &input);

        if (input == 0) {
            break;
        } else if (input > 0) {
            insertNode(list, list->data, input);
            printList(list);
        } else if (input < 0) {
            deleteNode(list, -input);
            printList(list);
        }
    }

    return 0;
}

关系:顺序表和链表是线性表的两种具体实现方式

  1. 线性表

    • 线性表是一种基本的数据结构,表示具有相同数据类型的元素按照线性次序排列的数据结构。
    • 线性表包括了一对一的关系,即每个元素都有一个直接前驱和一个直接后继。
  2. 顺序表

    • 顺序表是线性表的一种顺序存储结构,它使用数组等连续的存储空间来存储元素。
    • 顺序表中的元素在物理内存中是相邻的,通过数组下标可以直接访问元素。
    • 顺序表支持随机存取,即可以直接访问表中任意位置的元素。
  3. 链表

    • 链表是线性表的一种链式存储结构,它通过指针将元素按照一定的逻辑次序连接起来。
    • 链表的元素在物理内存中可以是不相邻的,每个元素包含数据域和指针域。
    • 链表包括单链表、双链表和循环链表等不同的类型。
  • 选择原则

    • 顺序表适用于频繁按位置访问元素的场景,链表适用于频繁插入和删除元素的场景。
    • 选择合适的存储方式取决于具体的应用需求。
  • 应用场景

    • 顺序表常用于静态查找、索引和需要频繁访问元素的场景。
    • 链表常用于动态存储、频繁插入和删除元素的场景。

 通过深入理解线性表、顺序表和链表的特点和实现方式,我们能够更好地选择和设计数据结构,以满足不同问题的需求。在实际应用中,合理选择和灵活运用这些数据结构能够提高程序的效率和性能。

  • 29
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值