450 lines
11 KiB
C
450 lines
11 KiB
C
/* 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");
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|