5. 08 C语言 数据结构

来源:互联网 发布:学java去哪儿好 编辑:程序博客网 时间:2024/05/01 05:50

链表: 

         链表Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer) 

        使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大 

 

 

二叉树: 

 

在今天上课代码的基础上完成以下要求: 

 

1. 输出年龄 < 18的学生; 

2. 根据学号删除学生; 

 

选做题: 

3. 按照学生学号排序 

 

// 

//  main.c 

//  Data structure_Lecture 

// 

//  Created by Knight on 5/8/15. 

//  Copyright (c) 2015 Knight. All rights reserved. 

// 

 

#include <stdio.h> 

#include <stdlib.h> 

#include <string.h> 

 

#define STUDENTS_OF_CLASS 3 

 

typedef struct Student { 

     

    char number[20];        //数据域 

    int age; 

     

    struct Student *next;   //指针域,指向下一个节点 

     

} Student; 

 

#pragma mark - 遍历输出链表 

 

void printLinkedList(Student *head) { 

     

    printf("---------------------------\n"); 

     

    //头指针(head)所指向的数据域为空,所以直接跳过头节点 

    Student *p = head->next; 

     

    printf("Number     Age\n"); 

     

    while (p != NULL) { 

         

        printf("%s\t\t ",p->number); 

        printf("%d\n", p->age); 

        p = p->next; 

    } 

     

    printf("---------------------------\n"); 

} 

 

#pragma mark - add(添加一个节点) 

 

void add(Student *head) { 

     

    Student *newStudent = (Student *)malloc(sizeof(Student)); 

    printf("Please input student's number: \n"); 

    fgets(newStudent->number20stdin); 

    newStudent->number[strlen(newStudent->number)-1]=0; 

     

    printf("Please input student's age: \n"); 

    scanf("%d", &newStudent->age); 

    getchar(); 

    newStudent->next = NULL;    //每创建一个学生成员,都要把指针域赋空 

     

    //找到最后一个节点 

    //指针p指向头节点,不要直接使用头指针 

    Student *p = head; 

     

    while (p->next != NULL) { 

         

        p = p->next;  //p指针向后移动一个节点 

    } 

     

    p->next = newStudent;  //指向新节点 

     

    printLinkedList(head); 

     

     

} 

 

#pragma mark - insert(插入节点) 

 

void insert(Student *head) { 

     

     

     

    Student *p = head; 

     

    Student *newStudent = (Student *)malloc(sizeof(Student)); 

    printf("Please input student's number: \n"); 

    fgets(newStudent->number20stdin); 

    newStudent->number[strlen(newStudent->number) - 1] = 0;  //去掉fgets接收的[回车] 

     

    printf("Please input student's age: \n"); 

    scanf("%d", &newStudent->age); 

    getchar(); 

    newStudent->next = NULL; 

     

    //将新节点插入到第1个位置(注意:下面两行代码不能交换顺序) 

    newStudent->next = p->next; 

    p->next = newStudent; 

     

     

     

    printLinkedList(head); 

} 

 

#pragma mark - delete(删除节点) 

 

void delete(Student *head) { 

     

    Student *p = head; 

     

    //这里的逻辑是删除头节点之后的第一个节点 

    Student *delete = p->next; 

     

    //移动p[要删除的节点的上一个节点] 

    p->next = delete->next; 

     

    free(delete); 

    printLinkedList(head); 

} 

 

#pragma mark - 第一题输出年龄 < 18的学生 

 

void ageBelowEighteen(Student *head) { 

     

    Student *p = head->next; 

     

    printf("Students(Age < 18): \n"); 

    printf("Number     Age\n"); 

     

    while (p != NULL) { 

         

        if (p->age < 18) { 

             

            printf("%s\t\t ",p->number); 

            printf("%d\n", p->age); 

        } 

         

        p = p->next; 

    } 

     

} 

 

#pragma mark - 第二题根据学号删除学生 

 

void deleteStudentWithSpecifiedNumber(Student *head) { 

     

    char deleteNum[20] = {'0'}; 

     

    printf("Input student number you want to delete: \n"); 

     

    scanf("%s",deleteNum); 

     

    getchar(); 

     

     

    Student *p = head;    //p指向链表头 

     

    Student *delete = NULL; 

     

    //p->next指向不为空,说明p所指向的节点后面还有节点,执行循环体 

    while (p->next != NULL) { 

         

        //判断p->next->numberdeleteNum是否一样,如果第一次执行循环,这里的p->next->number就是第一个节点的number(头节点没有数据域,不用检查) 

        if (strcmp(p->next->number, deleteNum) == 0) { 

             

            //如果满足条件,delete指向p->next,这时pdelete前面一个节点的位置 

            delete = p->next; 

             

            //需要检查delete所指的节点后面还有没有其他节点 

            //如果delete后面还有节点 

            if (delete->next != NULL) { 

                 

                //p->next重新定义指向,p->next指向delete->next 

                p->next = delete->next; 

                 

                //释放delete所指节点的内存,即删除delete所指向的节点 

                free(delete); 

                 

                //这里应该使用continue跳过本次循环,不执行后面的p = p->next; 如果没有continue,如果遇到有相邻两个节点符合删除条件,则只会删除第一个节点,第二个节点不会删除 

                continue; 

             

            //delete所指向的节点就是链尾 

            } else { 

                 

                //则直接删除delete所指向的节点 

                free(delete); 

                //p指向的节点应该变成链尾 

                p->next = NULL; 

                //跳出循环,如果这里没有break语句,本次循环还要移动一次p指针的位置,这样一来p指向链表之外的未知区域,再次判断while循环条件时就会出错。 

                break; 

            } 

             

        } 

       

        p = p->next; 

        

    } 

     

    printLinkedList(head); 

 

} 

 

 

#pragma mark - 第三题:按照学生学号排序 

 

void sortByNumber(Student *head) { 

     

    //定义一个新链表,用于排序 

    Student *newHead = (Student *)malloc(sizeof(Student)); 

    newHead->next = NULL; 

     

    Student *p1 = newHead; 

     

    //定义max指针,max->next指向循环找到的还未排序的最大的数(学生的number) 

    Student *max = head; 

     

    //定义temp指针,用于提取找到的最大的数 

    Student *temp = head; 

     

    //定义指向头节点的指针p2 

 

    Student *p2 = head->next; 

     

    //外层循环控制已排好序的数(已经排好了i个数) 

    for (int i = 0; i < STUDENTS_OF_CLASS; i++) { 

         

        max = head; 

         

        p2 = head->next; 

        //通过内层循环,找到本次遍历找到最大的数 

        for (int j = 0; j < STUDENTS_OF_CLASS - i; j++) { 

             

            if (p2->next != NULL && strcmp(max->next->number, p2->next->number) < 0) { 

                 

                //max->next指向当前判断的最大数 

                max = p2; 

                 

                //移动p2 

                p2 = p2->next; 

                 

                continue; 

                 

            } 

            //移动p2 

            p2 = p2->next; 

             

        } 

         

         

        //temp指向本次遍历找到的最大数 

        temp = max->next; 

         

        //max->next重新指向最大数后面的一个数,防止链表断裂 

        max->next = temp->next; 

         

        //最大数所在节点脱离原来的链表此时这个最大数只被temp指向 

        temp->next = NULL; 

         

        //把刚获得的最大数添加到新链表的末端 

        while (p1->next != NULL) { 

             

            p1 = p1->next;  //p指针向后移动一个节点 

        } 

         

        p1->next = temp;  //指向新找到的最大数 

     

         

    } 

    //新链表已经是原来链表各个节点排序之后的所形成的链表,遍历输出新链表的各节点 

    printf("Sorted linked list: \n"); 

    printLinkedList(newHead); 

     

    //原链表已被清空,只有一个头节点(head) 

    printf("Original linked list: \n"); 

    printLinkedList(head); 

} 

 

 

#pragma mark - mian函数 

 

int main(int argc, const char * argv[]) { 

 

    //根据Student结构体所占的内存大小分配内存空间,返回一个指向Student类型结构体的指针,并把指针给head(头指针) 

    //单向链表不能移动head指针,防止前面的节点无法访问. 

    Student *head = (Student *)malloc(sizeof(Student)); 

     

    //next赋为NULL  (1.防止dangling pointer ; 2.标记Linked list结束) 

    head->next = NULL; 

     

    for (int i = 0; i < STUDENTS_OF_CLASS; i++) { 

         

        add(head); 

    } 

 

    ageBelowEighteen(head); 

     

    deleteStudentWithSpecifiedNumber(head); 

     

    insert(head); 

     

    delete(head); 

     

    sortByNumber(head);   //调用此函数会复写head所代表的链表 

 

 

    return 0; 

} 

 


0 0
原创粉丝点击