Data_Structure/作業/unit4/sList-v3.c
2025-01-20 21:30:53 +08:00

450 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.

/* sList.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* 定義一指向 FILE 的指標 */
FILE *fptr;
/* 函式的原型宣告 */
void init_f(void);
void insertStudent(int id, char* name, double score);
void readFromFile(const char* filename);
void saveToFile(const char* filename, int flag);
void insert(void);
void del(void);
void modify(void);
void display(void);
// 定義學生節點結構
typedef struct Student {
long int id;
char name[10];
double score;
struct Student *rlink;
struct Student *llink;
} Student;
Student *head, *pNode ,*tail, *current, *prev, *temp , *originalHead ,*originalTail;
//設一個 head將左右鏈結皆指向本身
void init_f() {
head = (Student *) malloc(sizeof(Student));
tail = (Student *) malloc(sizeof(Student));
// 初始化 head 和 tail
head->llink = NULL;
head->rlink = tail;
tail->llink = head;
tail->rlink = NULL;
// 初始化原始順序串列
originalHead = (Student *) malloc(sizeof(Student));
originalTail = (Student *) malloc(sizeof(Student));
originalHead->llink = NULL;
originalHead->rlink = originalTail;
originalTail->llink = originalHead;
originalTail->rlink = NULL;
}
// 在尾部插入新學生節點
void insertStudent(int id, char* name, double score) {
Student* newNode = (Student*)malloc(sizeof(Student));
newNode->id = id;
strcpy(newNode->name, name);
newNode->name[9] = '\0';
newNode->score = score;
// 插入到尾部之前
newNode->rlink = tail;
newNode->llink = tail->llink;
tail->llink->rlink = newNode;
tail->llink = newNode;
}
/* 新增函數:插入節點到原始順序串列 */
void insertOriginalList(int id, char* name, double score) {
Student* newNode = (Student*)malloc(sizeof(Student));
newNode->id = id;
strncpy(newNode->name, name, 9);
newNode->name[9] = '\0';
newNode->score = score;
// 插入到原始串列尾部之前
newNode->rlink = originalTail;
newNode->llink = originalTail->llink;
originalTail->llink->rlink = newNode;
originalTail->llink = newNode;
}
// 讀檔
void readFromFile(const char* filename) {
char line[100];
FILE* fptr = fopen(filename, "r");
if (fptr == NULL) {
printf("無法打開檔案 %s\n", filename);
return;
}
long int id;
char name[10];
double score;
while(fgets(line ,sizeof(line) ,fptr)!=NULL){
if(sscanf(line,"%ld\t%9s\t%lf", &id, name, &score) == 3){
insertStudent(id, name, score);
insertOriginalList(id, name, score); // 插入原始順序串列
}
}
fclose(fptr);
printf("顯示檔案資料\n");
}
// 存檔
void saveToFile(const char* filename , int flag) {
FILE* fptr = fopen(filename, "w");
if (fptr == NULL) {
printf("無法打開檔案 %s 進行寫入\n", filename);
return;
}
if(flag == 2){
Student* current = head->rlink;
while (current != tail ) {
fprintf(fptr, "%ld\t%s\t%.lf\n", current->id, current->name, current->score);
current = current->rlink;
}
}else if(flag == 1){
Student* current = originalHead->rlink;
while (current != originalTail ) {
fprintf(fptr, "%ld\t%s\t%.lf\n", current->id, current->name, current->score);
current = current->rlink;
}
}
fclose(fptr);
printf("資料已成功\儲存到 %s\n", filename);
}
//顯示串列資料
void printStudentList() {
Student* current = head->rlink;
printf("\n*******************************");
if (current != NULL) {
printf("\n%6s %10s %8s\n", "ID", "Name", "Score");
printf("-------------------------------\n");
while (current != tail) {
printf("%6ld %10s %8.1f\n", current->id,current->name, current->score);
/* 將指標移到下一個節點 */
current = current->rlink;
}
}
/* 若是空的,則輸出鏈結串列無資料 */
else {
printf("\n鏈結串列無資料\n");
}
printf("*******************************\n\n");
}
/* 新增顯示原始順序資料的函數 */
void printOriginalList() {
Student* current = originalHead->rlink;
printf("\n*******************************");
if (current != originalTail) {
printf("\n%6s %10s %8s\n", "ID", "Name", "Score");
printf("-------------------------------\n");
while (current != originalTail) {
printf("%6ld %10s %8.1f\n", current->id, current->name, current->score);
current = current->rlink;
}
} else {
printf("\n鏈結串列無資料\n");
}
printf("*******************************\n\n");
}
void sort_id(){
Student* temp ;
Student* current;
//若沒有資料或只有一筆資料
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->id > temp->id){
// 只使用兩個節點進行節點交換
// 要注意指標改變後的順序
// 若下列程式順序交換指標指向的位址會出錯
// 也可以多宣告兩個節點 紀錄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_score(){
Student* temp;
Student* current;
//若沒有資料或只有一筆資料
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->score < temp->score){
// 只使用兩個節點進行節點交換
// 要注意指標改變後的順序
// 若下列程式順序交換指標指向的位址會出錯
// 也可以多宣告兩個節點 紀錄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;
}
}
}
}
int main(){
init_f();
readFromFile("list.txt");
printStudentList();
int flag = 0;
/* 利用一選單讓使用選擇功能項目 */
int choice;
do {
printf("************************\n");
printf("鏈結串列的運作選單\n");
printf("1. 加入一節點\n");
printf("2. 刪除一節點\n");
printf("3. 修改一節點\n");
printf("4. 顯示所有節點\n");
printf("5. 顯示原始輸入順位的資料\n");
printf("6. 顯示成績由高至低排列\n");
printf("7. 顯示ID由小到大排列\n");
printf("8. 結束\n");
printf("請選擇: ");
scanf("%d", &choice);
switch (choice) {
case 1:
insert();
break;
case 2:
del();
break;
case 3:
modify();
break;
case 4:
printStudentList();
break;
case 5:
printOriginalList();
flag = 1;
break;
case 6:
sort_score();
printStudentList();
flag = 2;
break;
case 7:
sort_id();
printStudentList();
flag = 2;
break;
case 8:
printf("\n程式結束\n");
saveToFile("list.txt",flag);
exit(0);
default:
printf("輸入號碼不正確,請重新輸入\n");
}
printf("\n");
} while(choice != 8);
getchar();
return 0;
}
/* 按照分數由大至小加入一節點於鏈結串列 */
void insert()
{
/* 利用 malloc() 函式配置記憶體*/
Student* newNode = (Student*)malloc(sizeof(Student));
printf("\n請輸入ID: ");
scanf("%ld", &newNode->id);
printf("請輸入姓名: ");
scanf("%s", newNode->name);
printf("請輸入分數: ");
scanf("%lf", &newNode->score);
/* 加入一節點於鏈結串列 */
current = head->rlink;
prev = head;
// 插入到尾部之前
newNode->rlink = tail;
newNode->llink = tail->llink;
tail->llink->rlink = newNode;
tail->llink = newNode;
// 插入原始順序串列
insertOriginalList(newNode->id, newNode->name, newNode->score);
}
void deleteFromOriginalList(long int deleteID) {
Student* current = originalHead->rlink;
Student* prev = originalHead;
while (current != originalTail) {
if (current->id == deleteID) {
current->rlink->llink = prev;
prev->rlink = current->rlink;
free(current);
break;
}
prev = current;
current = current->rlink;
}
}
/* 刪除某一節點*/
void del()
{
long int deleteID;
/* 將 current 指標指向 head 的下一個節點 */
current = head->rlink;
prev = head;
/* 先判斷鏈結串列是否為空 */
if (current != NULL) {
/* 若不是空的,則找尋欲刪除的節點 */
printf("\n請輸入欲刪除的 ID: ");
scanf("%ld", &deleteID);
/* 找尋欲刪除的節點 */
while ((current != tail) && (current->id != deleteID)) {
prev = current;
current = current->rlink;
}
/* 若找到,則將它刪除 */
if (current != tail) {
current->rlink->llink = prev;
prev->rlink = current->rlink;
printf("ID: %ld 已刪除\n", current->id);
deleteFromOriginalList(deleteID);
free(current);
}
/* 若沒有找到,則輸出找不到欲刪除節點的訊息*/
else {
printf("\n找不到欲刪除的節點\n");
}
}
/* 若是空的,則輸出鏈結串列是空的訊息 */
else {
printf("鏈結串列是空的\n");
}
}
/* 修改某一節點 */
void modify()
{
Student *temp;
long int modifyID;
double modifyScore;
int flag = 0;
printf("\n請輸入欲修改節點的 ID: ");
scanf("%ld", &modifyID);
current = head->rlink;
prev = head;
/* 找尋欲修改的節點 */
while (current != tail) {
if (current->id == modifyID) {
printf("目前欲修改節點的資料如下:\n");
printf("%6ld %10s %8.1f\n\n", current->id,
current->name, current->score);
printf("請輸入欲修改的分數: ");
scanf("%lf", &modifyScore);
current->score = modifyScore;
flag = 1;
break;
}
else {
prev = current;
current = current->rlink;
}
}
/* 判斷是否有找到欲修改的節點 */
if (flag != 0) {
/* 將 current 的節點指定給 temp */
temp = current;
prev->rlink = current->rlink;
/* 將 temp 節點加入於鏈結串列 */
current = head->rlink;
prev = head;
while ((current != tail) && (temp->score < current->score)) {
prev = current;
current = current->rlink;
}
prev->rlink = temp;
temp->rlink = current;
}
else {
printf("找不到欲修改的節點\n");
}
}