1. 程式人生 > >進擊的小白Day013——通訊錄(三)

進擊的小白Day013——通訊錄(三)

今天重新把通訊錄的程式完善了一下,可以完結了,通訊錄這種程式真的很適合來訓練結構體、指標和連結串列方面的知識。

貼程式碼:

#include <stdio.h>
#include <stdlib.h>  
#include <malloc.h>  
#define MAX 100

/*建立結構體連結串列,固定結構,背下來*/
typedef struct people
{
	char name[MAX];
	char sex[MAX];
	int age;
	long long int tel;
	char addr[MAX];
	struct people *pNext;
}Node, *pNode;  /*Node為結構體變數,pNode為結構體指標變數,也可以只寫Node,在定義指標的時候寫成(Node *p)*/

/*定義全域性變數,記錄最後錄入的聯絡人的節點數*/
int num = 0;

int main(void)
{
	int flag;
	char ch;
	pNode pHead = NULL;  /*首次定義頭指標需要置零*/
	pNode CreatList(void);
	pNode CreatMember(pNode);
	void DeleteMember(pNode);
	void DeleteList(pNode);
	void FindMember(pNode);
	void ModifyMember(pNode);
	void TraverseList(pNode);
	void DeleteAll(pNode);
	void SortList(pNode);
	
	while (1)
	{ 
		printf("1.新增聯絡人資訊\n2.刪除指定聯絡人資訊\n3.查詢指定聯絡人資訊\n4.修改指定聯絡人資訊\n5.顯示所有聯絡人資訊\n6.清空所有聯絡人\n7.以名字排序所有聯絡人\n");
		printf("請輸入要進行的操作:");
		scanf_s("%d", &flag);
		printf("\n");

		while (getchar() != '\n')
		{
			ch = getchar();
		}

		switch (flag)
		{
			case 1:
			{
				/*首次錄入聯絡人*/
				if (num == 0)
				{
					pHead = CreatList();
				}
				/*重複錄入聯絡人*/
				else
				{
					pHead = CreatMember(pHead);
				}
				printf("\n");
				break;
			}
			case 2:
			{
				/*剩餘聯絡人超過1人時,令連結串列為空表*/
				if (num == 1)
				{
					DeleteList(pHead);
				}
				/*正常刪除*/
				else
				{
					DeleteMember(pHead);
				}
				printf("\n");
				break;
			}
			case 3:
			{
				FindMember(pHead);
				printf("\n");
				break;
			}
			case 4:
			{
				ModifyMember(pHead);
				printf("\n");
				break;
			}
			case 5:
			{
				/*連結串列中有聯絡人時,正常遍歷*/
				if (num > 0)
				{
					TraverseList(pHead);
				}
				/*空連結串列*/
				else
				{
					printf("無聯絡人。");
				}
				printf("\n");
				break;
			}
			case 6:
			{
				DeleteAll(pHead);
				printf("\n");
				break;
			}
			case 7:
			{
				SortList(pHead);
				printf("\n");
				break;
			}
		}
		printf("現有%d個聯絡人。\n\n\n", num);
	}
	return 0;
}

/*首次錄入聯絡人,建立一個新的連結串列*/
pNode CreatList(void)
{
	/*定義頭節點、尾節點、新節點*/
	pNode pHead, pTail, pNew;  
	pHead = (pNode)malloc(sizeof(Node));  /*為頭指標開闢一塊記憶體*/
	pTail = pHead;  /*空連結串列的頭節點就是尾節點*/
	pTail->pNext = NULL;  /*尾節點指向空值*/

	/*輸入資料給新節點*/
	pNew = (pNode)malloc(sizeof(Node));  /*為新節點開闢記憶體*/
	printf("請輸入聯絡人姓名:");
	scanf_s("%s", &pNew->name, MAX);
	printf("請輸入聯絡人性別:");
	scanf_s("%s", &pNew->sex, MAX);
	printf("請輸入聯絡人年齡:");
	scanf_s("%d", &pNew->age);
	printf("請輸入聯絡人電話:");
	scanf_s("%lld", &pNew->tel);
	printf("請輸入聯絡人地址:");
	scanf_s("%s", &pNew->addr, MAX);

	/*新節點接入連結串列*/
	pTail->pNext = pNew;  /*令原來的尾節點指向新節點*/
	pNew->pNext = NULL;  /*新節點指向空值*/
	pTail = pNew;  /*新節點成為新的尾節點,原來的尾節點成為中間節點*/

	/*錄入聯絡人+1*/
	num++;

	return pHead;
}

/*重複錄入聯絡人,將新的聯絡人接到原有的連結串列中*/
pNode CreatMember(pNode p)
{
	/*定義新連結串列的頭節點、尾節點、新節點、臨時節點*/
	pNode pHead, pTail, pNew, pSwap, pRepeat;
	char a[MAX];
	pHead = p;  /*將原有的連結串列賦給pHead*/
	pRepeat = p->pNext;

	/*尋找原有連結串列的最後一個節點*/
	pSwap = NULL;  /*定義一個pVal來臨時儲存最後一個節點的資料*/
	while (p != NULL)
	{
		pSwap = p;  /*pVal始終為p的前一個節點,當遍歷結束時,p為空,pVal即為最後一個節點*/
		p = p->pNext;
	}
	pTail = pSwap;  /*令pTail成為連結串列最後一個節點*/
	pTail->pNext = NULL;  /*尾節點指向空值*/

	/*輸入資料給新節點*/
	pNew = (pNode)malloc(sizeof(Node));
	printf("請輸入聯絡人姓名:");
	scanf_s("%s", &pNew->name, MAX);
	printf("請輸入聯絡人性別:");
	scanf_s("%s", &pNew->sex, MAX);
	printf("請輸入聯絡人年齡:");
	scanf_s("%d", &pNew->age);
	printf("請輸入聯絡人電話:");
	scanf_s("%lld", &pNew->tel);
	printf("請輸入聯絡人地址:");
	scanf_s("%s", &pNew->addr, MAX);

	/*判斷新錄入的聯絡人是否已存在*/
	while (pRepeat != NULL)
	{
		if (strcmp(pNew->name, pRepeat->name) == 0)
		{
			printf("聯絡人已存在!\n");
			return pHead;
		}
		pRepeat = pRepeat->pNext;
	}

	/*新節點接入連結串列*/
	pTail->pNext = pNew;  /*令原來的尾節點指向新節點*/
	pNew->pNext = NULL;  /*新節點指向空值*/
	pTail = pNew;  /*新節點成為新的尾節點,原來的尾節點成為中間節點*/

	/*錄入聯絡人+1*/
	num++;

	return pHead;
}

/*刪除第一個聯絡人,令連結串列為空*/
void DeleteList(pNode p)
{
	/*定義臨時節點*/
	pNode pSwap;
	char a[MAX];

	printf("請輸入要刪除的聯絡人姓名:");

	pSwap = p;  /*將聯絡人鏈表頭節點賦值給臨時節點*/
	scanf_s("%s", a, MAX);

	if (strcmp(pSwap->pNext->name, a) == 0)  /*檢查姓名是否匹配*/
	{
		pSwap = NULL;

		/*刪除聯絡人-1*/
		num--;
	}
	else
	{
		printf("聯絡人不存在!");
	}
}

/*刪除指定聯絡人*/
void DeleteMember(pNode p)
{
	/*定義臨時節點*/
	pNode pSwap, pVal;
	char a[MAX];

	printf("請輸入要刪除的聯絡人姓名:");

	pSwap = p;  /*將聯絡人鏈表頭節點賦值給臨時節點*/
	pVal = p;
	scanf_s("%s", a, MAX);

	/*遍歷*/
	while (pSwap != NULL)
	{
		if (strcmp(pSwap->name, a) == 0)  /*檢查姓名是否匹配*/
		{
			pVal->pNext = pVal->pNext->pNext;
			break;
		}
		pVal = pSwap;  /*儲存要刪除的節點的前一節點*/
		pSwap = pSwap->pNext;
	}
	if (pSwap == NULL)
	{
		printf("未找到聯絡人!\n");
	}

	/*刪除聯絡人-1*/
	num--;
}

/*查詢聯絡人*/
void FindMember(pNode p)
{
	/*定義臨時節點*/
	pNode pSwap;
	char a[MAX];

	printf("請輸入要查詢的聯絡人姓名:");
	scanf_s("%s", a, MAX);

	pSwap = p->pNext;  /*將聯絡人鏈表頭節點賦值給臨時節點*/

	/*遍歷*/
	while (pSwap != NULL)
	{
		if (strcmp(pSwap->name, a) == 0)  /*檢查姓名是否*/
		{
			printf("%s	", pSwap->name);
			printf("%s	", pSwap->sex);
			printf("%d	", pSwap->age);
			printf("%lld	", pSwap->tel);
			printf("%s\n", pSwap->addr);
			break;
		}
		pSwap = pSwap->pNext;
	}
	if (pSwap == NULL)
	{
		printf("未找到聯絡人!\n");
	}
}

/*修改聯絡人*/
void ModifyMember(pNode p)
{
	/*定義臨時節點*/
	pNode pSwap;
	char a[MAX];

	printf("請輸入要查詢的聯絡人姓名:");
	scanf_s("%s", a, MAX);

	pSwap = p->pNext;  /*將聯絡人鏈表頭節點賦值給臨時節點*/

	/*遍歷*/
	while (pSwap != NULL)
	{
		if (strcmp(pSwap->name, a) == 0)  /*檢查姓名是否*/
		{
			/*輸入資料給新節點*/
			printf("請輸入聯絡人姓名:");
			scanf_s("%s", &pSwap->name, MAX);
			printf("請輸入聯絡人性別:");
			scanf_s("%s", &pSwap->sex, MAX);
			printf("請輸入聯絡人年齡:");
			scanf_s("%d", &pSwap->age);
			printf("請輸入聯絡人電話:");
			scanf_s("%lld", &pSwap->tel);
			printf("請輸入聯絡人地址:");
			scanf_s("%s", &pSwap->addr, MAX);
			break;
		}
		pSwap = pSwap->pNext;
	}
	if (pSwap == NULL)
	{
		printf("未找到聯絡人!\n");
	}
}

/*遍歷輸出所有聯絡人*/
void TraverseList(pNode pHead)
{
	/*定義臨時節點*/
	pNode p;
	p = pHead->pNext;  /*把pHead->pNext而不是pHead賦給p,是因為pHead的資料域本身沒有意義,因此只需要賦值pHead->pNext,即將第一個節點的資料域和指標域賦給p*/
	
	/*執行遍歷*/
	while (p != NULL)
	{
		printf("%s	", p->name);
		printf("%s	", p->sex);
		printf("%d	", p->age);
		printf("%lld	", p->tel);
		printf("%s\n", p->addr);
		p = p->pNext;
	}
}

/*刪除第一個聯絡人,令連結串列為空*/
void DeleteAll(pNode p)
{
	/*定義臨時節點*/
	pNode pSwap;

	/*連結串列清空*/
	pSwap = p;  /*將聯絡人鏈表頭節點賦值給臨時節點*/
	pSwap = NULL;

	/*聯絡人數量歸零*/
	num = 0;
}

/*排序*/
void SortList(pNode pp)
{
	/*定義臨時節點*/
	pNode p, q;
	int i, j, m = num;

	/*進行num-1輪氣泡排序*/
	for (i = 0; i < num - 1; i++)
	{
		/*頭指標重置*/
		p = pp;
		q = pp->pNext;

		/*單論氣泡排序,將最大的數送到最下面*/
		for (j = 0; j < m - 1; j++)
		{
			if (q->name[0] > q->pNext->name[0])
			{
				p->pNext = q->pNext;
				q->pNext = q->pNext->pNext;
				p->pNext->pNext = q;
				q = p->pNext;
			}
			q = q->pNext;
			p = p->pNext;
		}
		m--;
	}
}

在這邊寫一個完整的連結串列氣泡排序單步教程吧,免得以後忘記了。
首先說一下,關於“p->next = q->next”語句的理解:
① “p->next”看作一個過程,是個動詞,理解為“p的下一個節點是XX”;
② “q->next”看作一個整體,是個名詞,代表一個節點,理解為“p的下一個節點”。