Data_Structure/作業/unit4/DS4_v2(try).c
2025-01-20 21:30:53 +08:00

473 lines
11 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <conio.h>
#define MAX_NAME_LENGTH 24
//宣告函式原型
void init_f();
void insertStudent(char* name, int english, int math);
void modify_list();
void add_data(char* name, int english, int math);
void remove_data(char* name);
void readStudentsFromFile(char* filename);
void printStudentList();
void sort_name();
void sort_eng();
void sort_math();
void choose_subject();
void find_student(int number , int mode);
// 定義學生節點結構
typedef struct Student {
char name[MAX_NAME_LENGTH];
int english;
int math;
struct Student* llink;
struct Student* rlink;
} Student;
Student *head, *tail, *current, *prev, *temp;
FILE* file;
//設一個 head將左右鏈結皆指向本身
void init_f() {
head = (Student *) malloc(sizeof(Student)); // 直接用 head
head->llink = head; // 左鏈結指向自己
head->rlink = head; // 右鏈結指向自己
tail = head;
}
// 在尾部插入新學生節點
void insertStudent(char* name, int english, int math) {
Student* newNode = (Student*)malloc(sizeof(Student));
strcpy(newNode->name, name);
newNode->english = english;
newNode->math = math;
if(head->rlink == tail) {
// 這是第一個插入的節點
head->rlink = newNode;
tail->llink = newNode;
newNode->llink = head;
newNode->rlink = tail;
} else {
//不是第一筆 插入尾部
newNode->llink = tail->llink;
newNode->rlink = tail;
tail->llink->rlink = newNode;
tail->llink = newNode;
}
}
// 執行***後的增加或減少資料
void modify_list(){
char name[MAX_NAME_LENGTH];
int english, math;
char line[100];
while(fgets(line, sizeof(line), file)!=NULL){
if(line[0]=='+'){
sscanf(line+2, "%23[^\t]\t%d\t%d\n", name, &english, &math);
printf("\n*******************************\n");
printf("增加一筆資料\n\n");
add_data(name, english, math);
printStudentList();
}else if(line[0]=='-'){
sscanf(line+2, "%23[^\t]\t%d\t%d\n", name, &english, &math);
printf("\n*******************************\n");
printf("刪除一筆資料\n\n");
remove_data(name);
printStudentList();
}
}
fclose(file);
}
//增加資料
void add_data(char* name, int english, int math){
Student* newNode = (Student*)malloc(sizeof(Student));
strcpy(newNode->name, name);
newNode->english = english;
newNode->math = math;
newNode->llink = tail->llink;
newNode->rlink = tail;
tail->llink->rlink = newNode;
tail->llink = newNode;
printf("%s 已增加\n\n", name);
}
//減少資料
void remove_data(char* name){
prev = head;
current = head->rlink;
while(current!=tail &&strcmp(name,current->name)!=0){
prev=current;
current=current->rlink;
}
if(current != tail){
current->rlink->llink = prev;
prev->rlink = current->rlink;
printf("%s 已刪除\n\n", name);
free(current);
}else /* 找不到資料則顯示錯誤 */
printf(" %s 不在串列中\n", name);
}
// 從文件讀取學生資料
void readStudentsFromFile(char* filename) {
file = fopen(filename, "r");
if (file == NULL) {
printf("無法開啟檔案 %s\n", filename);
return;
}
char line[100];
int lineCount = 0;
// 跳過前四行
while (lineCount < 4 && fgets(line, sizeof(line), file)) {
lineCount++;
}
// 讀取學生資料
char name[MAX_NAME_LENGTH];
int english, math;
// %[ ]表示要讀入一個字符集合
// %23[^\t]為「讀取最多23個字符直到遇到\t為止」 ^為非 不是\t就讀
// 若成功讀取到資料會回傳3 若讀取失敗 只讀到name或沒讀到資料則回傳值不等於3
while(fgets(line, sizeof(line), file)!=NULL){
if(isalpha(line[0])){
sscanf(line, "%23[^\t]\t%d\t%d\n", name, &english, &math);
insertStudent(name, english, math);
}else if(line[0]=='*'){
break;
}
}
// 此flocse為測試用 正常使用應在modify_list的尾端
// fclose(file);
}
// 列印學生列表
void printStudentList() {
current = head->rlink;
printf("\n從頭開始\n");
printf("\n姓名\t\t英文\t數學\n");
printf("--------------------------------\n");
while (current != tail) {
printf("%-15s\t%d\t%d\n", current->name, current->english, current->math);
current = current->rlink;
}
current = tail->llink;
printf("\n從尾開始\n");
printf("\n姓名\t\t英文\t數學\n");
printf("--------------------------------\n");
while (current != head) {
printf("%-15s\t%d\t%d\n", current->name, current->english, current->math);
current = current->llink;
}
}
//依照名字進行排序
void sort_name(){
//若沒有資料或只有一筆資料
if (head->rlink == tail || head->rlink->rlink == tail) {
return;
}
int flag = 1;
while(flag){
flag = 0;
current = head->rlink;
while(current->rlink != tail){
temp = current->rlink;
if(strcmp(current->name,temp->name) > 0){
// 只使用兩個節點進行節點交換
// 要注意指標改變後的順序
// 若下列程式順序交換指標指向的位址會出錯
// 也可以多宣告兩個節點 紀錄current->llink及temp->rlink
// 這樣就可以無腦不管順序
temp->llink = current->llink;
current->rlink = temp->rlink;
temp->rlink->llink = current;
temp->rlink = current;
current->llink->rlink = temp;
current->llink = temp;
flag = 1;
}
else{
current = current->rlink;
}
}
}
}
//依照英文成績進行排序
void sort_eng(){
//若沒有資料或只有一筆資料
if (head->rlink == tail || head->rlink->rlink == tail) {
return;
}
int flag = 1;
while(flag){
flag = 0;
current = head->rlink;
while(current->rlink != tail){
temp = current->rlink;
if(current->english < temp->english){
// 只使用兩個節點進行節點交換
// 要注意指標改變後的順序
// 若下列程式順序交換指標指向的位址會出錯
// 也可以多宣告兩個節點 紀錄current->llink及temp->rlink
// 這樣就可以無腦不管順序
temp->llink = current->llink;
current->rlink = temp->rlink;
temp->rlink->llink = current;
temp->rlink = current;
current->llink->rlink = temp;
current->llink = temp;
flag = 1;
}
else{
current = current->rlink;
}
}
}
}
//依照英文成績進行排序
void sort_math(){
//若沒有資料或只有一筆資料
if (head->rlink == tail || head->rlink->rlink == tail) {
return;
}
int flag = 1;
while(flag){
flag = 0;
current = head->rlink;
while(current->rlink != tail){
temp = current->rlink;
if(current->math < temp->math){
// 只使用兩個節點進行節點交換
// 要注意指標改變後的順序
// 若下列程式順序交換指標指向的位址會出錯
// 也可以多宣告兩個節點 紀錄current->llink及temp->rlink
// 這樣就可以無腦不管順序
temp->llink = current->llink;
current->rlink = temp->rlink;
temp->rlink->llink = current;
temp->rlink = current;
current->llink->rlink = temp;
current->llink = temp;
flag = 1;
}
else{
current = current->rlink;
}
}
}
}
//選擇科目及排名
void choose_subject() {
int subject, number;
char mode;
printf("\n輸入選擇的科目\n"
"1 數學 2 英文 ==> ");
mode = getche();
if (mode != '1' && mode != '2') {
printf("\n輸入錯誤\n");
return;
}
printf("\n輸入排名(輸入完畢請按Enter) ==> ");
scanf("%d", &number);
// 根據選擇的科目進行排序
if (mode == '1') {
sort_math();
} else {
sort_eng();
}
find_student(number, mode - '0');
// 顯示完整排名列表
printf("\n驗證如下");
printf("\n排名\t姓名\t\t英文\t數學");
printf("\n-----------------------------------\n");
current = head->rlink;
int actualRank = 1; // 實際排名(考慮同分)
int position = 1; // 位置計數
int prevScore = -1; // 前一個分數
while (current != tail) {
int currentScore;
if (mode == '1') {
currentScore = current->math;
} else {
currentScore = current->english;
}
// 如果當前分數與前一個分數不同,更新實際排名為當前位置
if (currentScore != prevScore) {
actualRank = position;
}
printf("%d\t%-15s\t%d\t%d\n",
actualRank,
current->name,
current->english,
current->math);
prevScore = currentScore;
position++; // 位置永遠加1
current = current->rlink;
}
}
//根據科目及排名找學生
void find_student(int number, int mode) {
current = head->rlink;
int actualRank = 1; // 實際排名
int position = 1; // 位置計數
int prevScore = -1; // 前一個分數
printf("\n*****************************\n");
printf("%s排名第%d的學生為\n\n",
(mode == 1) ? "數學" : "英文", number);
printf("姓名\t\t英文\t數學\n");
// 尋找第一筆資料的分數初始化prevScore
if (current != tail) {
prevScore = (mode == 1) ? current->math : current->english;
}
while (current != tail) {
int currentScore = (mode == 1) ? current->math : current->english;
// 如果當前分數與前一個分數不同,更新實際排名
if (currentScore != prevScore) {
actualRank = position;
}
// 如果找到目標排名,印出該生資料
if (actualRank == number) {
printf("%-15s\t%d\t%d\n",
current->name,
current->english,
current->math);
}
prevScore = currentScore;
position++;
current = current->rlink;
}
printf("*****************************\n");
}
//釋放所有節點
void freeAllNodes() {
current = head->rlink;
while (current != tail) {
Student* temp = current;
current = current->rlink;
free(temp);
}
free(head); // 釋放 head 節點
}
int main() {
char mode ,sort_mode;
init_f();
readStudentsFromFile("YunTechStudents.txt");
printStudentList();
modify_list();
while(1){
printf("\n******* 選擇進行排序或是排名第n名的學生 *******\n"
"*--------------------------------------*\n"
"* 1 進行排序 2 選擇排名第n名的學生 3 結束 *\n"
"\n請選擇功\能 ==> "); //不打成 功\能 在視窗中會變亂碼
mode = getche();
switch(mode){
case '1':
printf("\n\n選擇排序方式\n"
"*--------------------------------------*\n"
"1 名字 2 英文成績 3 數學成績 \n"
"\n請選擇排序方式 ==> ");
sort_mode = getche();
switch(sort_mode){
case '1':
printf("\n\n以名字進行排序\n");
sort_name();
printStudentList();
break;
case '2':
printf("\n\n以英文成績進行排序\n");
sort_eng();
printStudentList();
break;
case '3':
printf("\n\n以數學成績進行排序\n");
sort_math();
printStudentList();
break;
default:
printf("\n輸入錯誤\n");
break;
}
break;
case '2':
choose_subject();
break;
case '3':
printf("\n\n謝謝使用Bye~\n");
freeAllNodes();
return 0;
default:
printf("\n輸入錯誤\n");
break;
}
}
}