Cách xử lý loại bỏ sinh viên

Mình có đề như này mà làm đến phần loại bỏ sinh viên có điểm trung bình < 5 thì thử nhiều cách đều không được, mọi người giúp mình với ạ. Dưới đây là đề và code của mình.

Đề bài

Giả sử cần quản lý một lớp học bao gồm các sinh viên. Mỗi sinh viên gồm các thông tin sau: Họ Tên, Lớp, Số báo danh, Điểm trung bình. Anh (chị) hãy thực hiện các công việc sau:

  1. Cài đặt danh sách này bằng cấu trúc danh sách liên kết đơn.
  2. Với cấu trúc danh sách đã cài đặt, viết các chương trình con thực hiện các yêu cầu như sau:
    a) Nhập vào danh sách gồm n sinh viên
    b) Loại bỏ khỏi danh sách những sinh viên có điểm trung bình < 5
    c) Sắp xếp danh sách theo trường lớp tăng dần
    d) In ra màn hình danh sách sinh viên theo từng lớp

Source code

#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
struct sv
{
    char hoten[20];
    char lop[20];
    char sbd[10];
    float dtb;
};
struct NODE
{
    sv info;
    struct NODE* next;
};
struct LIST
{
    NODE *head;
    NODE *tail;
};
NODE* CreateNode (sv x)
{
    NODE *p;
    p=new NODE;
    if(p==NULL)  exit(1);
    p->info=x;
    p->next=NULL;
    return p;
}
void CreateList (LIST &L)
{
    L.head=L.tail=NULL;
}
void input (sv &x)
{
    printf("\n\tNhap Ten sinh vien: ");  fflush(stdin); gets(x.hoten);
    printf("\tNhap Lop: ");  fflush(stdin); gets(x.lop); 
	printf("\tNhap So bao danh: ");  fflush(stdin); gets(x.sbd); 
    printf("\tNhap Diem trung binh: "); scanf("%f", &x.dtb);
}
void AddLast (LIST &L, NODE *p)
{
    if(L.head==NULL)  L.head=L.tail=p;
    else
    {
        L.tail->next=p;
        L.tail=p;
    }
}
void nhap (LIST &L)//nhap sinh vien
{
    sv x;
 	int n;
 	printf("\nMoi nhap so sinh vien can them:");scanf("%d", &n);
 	printf("\nMoi nhap danh sach sinh vien.");
    for(int i=0;i<n;i++)
    {
        input(x);
        NODE *p=CreateNode(x);
        AddLast(L,p);
    } 
}
void output (sv x)
{
    printf("\n%s    %s     %s       %0.2f",x.hoten,x.lop,x.sbd,x.dtb);
}
void xuat (LIST L)//xuat danh sach sinh vien nhap vao
{
    NODE *p;
    p=L.head;
    while(p!=NULL)
    {
        output(p->info);
        p=p->next;
    }
}

void xuat2 (LIST L)//loai bo sinh cien co diem trung binh <5
{
    NODE *p;
    p=L.head;
    while(p!=NULL)
    {
    	if(p->info.dtb>=5)
        output(p->info);
        p=p->next;
    }
}

void xoa (LIST &L)
{
    NODE *p, *q,*tem;
    char a[10];
    p=L.head;
    q=NULL;
	tem=L.head;
	while (tem!=NULL)
	{
		while (p!=NULL)
	    {
	        if( p->info.dtb<5)    break;
	        q=p;
	        p=p->next;
	    }
	    if(q!=NULL)
	    {
	        if(p!=NULL)
	        {
	            q->next=p->next;
	            delete (p);
	            if(p==L.tail)  L.tail=q;
	            delete(p);
	        }
	    }
	    else
	    {
	        L.head=p->next;
	        delete(p);
	        if(L.head==NULL)  L.tail=NULL;
	    }
	    tem=tem->next;
	}
    
}

void selectionsort (LIST &L)
{
    NODE *p,*q,*min;
    p=L.head;
    sv temp;
    while (p!=L.tail)
    {
        min=p;
        q=p->next;
        while (q!=NULL)
        {
            if(q->info.dtb<min->info.dtb)  min=q;
            q=q->next;
        }
        temp=p->info;
        p->info=min->info;
        min->info=temp;
        p=p->next;
    }
}

int main()
{
    LIST L;
    NODE *p,*q,*moi;
    sv x;
    char chon;
    CreateList(L);
    nhap(L);
    printf("\nDanh sach sinh vien vua nhap la:\n");
    xuat(L);
    printf("\nDanh sach sinh vien sau khi loai bo nhung sinh vien co diem trung binh < 5 la:\n");
    xoa(L);
    xuat(L);
    printf("\nDanh sach sinh vien sau khi sap xep tang dan theo diem trong binh la:\n");
    selectionsort(L);
    xuat(L);
    getch();
}

Nếu có thể, bạn nên làm 1 DSLK có những hàm hoàn chỉnh.

  • Tạo danh sách.
  • Tạo nút (node).
  • Thêm nút vào đầu.
  • Thêm nút vào cuối.
  • Chèn nút tại 1 vị trí hoặc trước/sau 1 nút nào đó.
  • Xóa đầu.
  • Xóa cuối.
  • Xóa 1 nút nhất định khỏi danh sách. <==.

Đoạn xóa của bạn mình đọc thấy nó khá rườm rà, dùng quá nhiều biến tạm, vòng lặp và điều kiện. Mà xem ra quá trình thực hiện của bạn, biến tem chẳng có liên hệ gì với pq.

5 Likes

Mình đã làm lại và khi xóa các node ở giữa thì vẫn chạy bình thường nhưng khi xóa node đầu tiên thì lại không chạy được. đây là code:

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<iomanip>
using namespace std;
struct sv
{
    char hoten[20];
    char lop[20];
    char sbd[10];
    float dtb;
};
struct LinkedList{
    sv  data;
    struct LinkedList *next;
};

typedef struct LinkedList *node; 
 
node CreateNode(sv x){
    node temp; 
    temp = (node)malloc(sizeof(struct LinkedList)); 
    temp->next = NULL;
    temp->data = x; 
    return temp;
}

node AddTail(node head, sv x){
    node temp,p;
    temp = CreateNode(x);
    if(head == NULL){
        head = temp; 
    }
    else{
        p  = head;
        while(p->next != NULL){
            p = p->next;
        }
        p->next = temp;
    }
    return head;
}
 
 
node AddHead(node head, sv x){
    node temp = CreateNode(x); 
    if(head == NULL){
        head = temp; 
    }else{
        temp->next = head; 
        head = temp; 
    }
    return head;
}
 
node AddAt(node head, sv x, int position){
    if(position == 0 || head == NULL){
        head = AddHead(head, x); 
    }else{
        int k = 1;
        node p = head;
        while(p != NULL && k != position){
            p = p->next;
            ++k;
        }
 
        if(k != position){
            head = AddTail(head, x);
        }else{
            node temp = CreateNode(x);
            temp->next = p->next;
            p->next = temp;
        }
    }
    return head;
}
 
node DelHead(node head){
    if(head == NULL){
        printf("\nCha co gi de xoa het!");
    }else{
        head = head->next;
    }
    return head;
}
 
node DelTail(node head){
    if (head == NULL || head->next == NULL){
         return DelHead(head);
    }
    node p = head;
    while(p->next->next != NULL){
        p = p->next;
    }
    p->next = p->next->next; 
    return head;
}
 
node DelAt(node head, int position){
    if(position == 0 || head == NULL || head->next == NULL){
        head = DelHead(head);
    }else{
        int k = 1;
        node p = head;
        while(p->next->next != NULL && k != position){
            p = p->next;
            ++k;
        }
        if(k != position){
            head = DelTail(head);
        }else{
            p->next = p->next->next;
        }
    }
    return head;
}
 
int Search(node head, float value){// Tim node co gia tri < value
    int K = 0;
    for(node p = head; p != NULL; p = p->next){
        if(p->data.dtb < value){
            return K;
        }
        ++K;
    }
    return -1;
}
 
node DelByVal(node head, int value){ // xoa node co gia tri chi dinh
    int K = Search(head, value);
    while(K != -1){
        DelAt(head, K);
        K = Search(head, value);
    }
    return head;
}


node InitHead(){
    node head;
    head = NULL;
    return head;
}

void input (sv &x) // ham nhap thong tin sinh vien
{
    printf("\n\tNhap Ten sinh vien: ");  fflush(stdin); gets(x.hoten);
    printf("\tNhap Lop: ");  fflush(stdin); gets(x.lop); 
	printf("\tNhap So bao danh: ");  fflush(stdin); gets(x.sbd); 
    printf("\tNhap Diem trung binh: "); scanf("%f", &x.dtb);
}

node Input()// Nhap vao danh sach lien ket
{ 
    node head = InitHead();
    int n;
    sv x;
    do{
        printf("\nNhap so luong sinh vien : ");
        scanf("%d", &n);
        if(n<=0)
        	printf("\nHay nhap so luong sinh vien lon hon 0 !");
    }while(n <= 0);
 
    for(int i = 0; i < n; ++i){
        printf("\nSinh vien thu %d",i+1);
        input(x);
        node p=CreateNode(x);
        head = AddTail(head, x);
    }
    return head;
}

void output (sv x){
	cout<<"\n"<<setw(20)<<x.hoten<<setw(20)<<x.lop<<setw(20)<<x.sbd<<setw(20)<<x.dtb;
}

void Traverser(node head){
    printf("\n");
    cout<<"\n"<<setw(20)<<"HO TEN"<<setw(20)<<"LOP"<<setw(20)<<"SO BAO DANH"<<setw(20)<<"DIEM TRUNG BINH";
    for(node p = head; p != NULL; p = p->next){
        output(p->data);
    }
}
 
 
int Length(node head){
    int length = 0;
    for(node p = head; p != NULL; p = p->next){
        ++length;
    }
    return length;
}
 
int main(){
    printf("\n==========MOI NHAP VAO DANH SACH SINH VIEN==========");
    node head = Input();
    printf("\n==========DANH SACH SINH VIEN VUA NHAP VAO LA: ==========");
    Traverser(head);
 
    printf("\n==========DANH SACH SAU KHI LOAI BO NHUNG SINH VIEN CO DIEM TRUNG BINH < 5 LA: ==========");
    head = DelByVal(head, 5);
    Traverser(head);

    printf("\nBan co the thu them nhe!");
 
}
2 Likes
node DelHead(node head){
    if(head == NULL){
        printf("\nCha co gi de xoa het!");
    }else{
        head = head->next;
    }
    return head;
}
  1. Xóa phải dùng free() chứ, ở trên malloc() rồi phải trả lại cho người ta nha. Nếu không sẽ bị memory leak.
  2. LinkedList rất dễ bug, muốn debug thì print hết địa chỉ và thành phần từng node ra nha bạn. Hoặc dùng Debugger. Ngồi nhìn bằng mắt không ra đâu. :v:
4 Likes

A post was merged into an existing topic: Topic lưu trữ các post off-topic - version 3

83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?