鏈表-基礎
1. 數組
1.1 靜態數組
例子:int nums[5] = {0};struct person ps[5];
缺點:1,無法修改地址2,無法動態定義長度3,占用內存過大或過小4,增刪速度慢
優點數組的內存是連續開辟的,所以讀取速度快
1.2 動態數組
例子:int *nums = (int *) calloc(5,sizeof(int));struct person *ps = (struct person *)calloc(5,sizeof(struct person));
缺點:增刪速度慢編寫代碼較為復雜
優點:讀取效率高
2. 常用數據結構
1、數組結構:內存連續開辟
2、鏈表結構:離散開辟
3、樹
4、二叉樹(均衡二叉樹,非均衡二叉樹)
5、圖
3. 鏈表結構
分類:
單鏈表:
- 一個節點只記錄下一個節點的地址
雙鏈表:
- 一個節點即記錄下一個節點的地址,也記錄上一個節點的地址
4. 設計節點
需求:將多個學員信息設計為鏈表
單鏈表節點設計:
typedef struct student {//數據域char name[50];char sex[5];int num;double score;//指針域struct student *next; }Stu;
雙鏈表節點設計:
typedef truct student {//數據域char name[50];char sex[5];int num;double score;//指針域struct student *next;struct student *head; }Stu;
總結:
typedef struct 結構體名稱 {//數據域//指針域 }別名;
5. 靜態單鏈表
#include <stdio.h>
typedef struct student
{//數據域char name[50];char sex[5];int num;double score;//指針域struct student *next;
}Stu;
int main(int argc, char const *argv[])
{Stu s01 = {"張三", "男", 1, 99, NULL};Stu s02 = {"李四", "男", 2, 96, NULL};Stu s03 = {"王五", "女", 3, 97, NULL};Stu s04 = {"錢七", "男", 4, 93, NULL};Stu s05 = {"趙八", "女", 5, 97, NULL};Stu *head = &s01; //將s01作為首節點s01.next = &s02; //將s02設置為s01的下一個節點 s02.next = &s03;s03.next = &s04;s04.next = &s05;//鏈表的遍歷//pd:當前鏈表的節點Stu *pd = head;while(pd != NULL){printf("%s %s %d %.2lf\n", pd->name, pd->sex, pd->num, pd->score);//下一個節點賦值給當前節點,為下一輪循環pd = pd->next;}return 0;
}
6. 動態單鏈表
動態開辟內存,存儲結構體學生信息
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct student
{//數據域char name[50];char sex[5];int age;//指針域struct student *next;
}Stu;
int main(int argc, char const *argv[])
{Stu *s01 = calloc(1,sizeof(Stu));strcpy(s01->name, "陳晴朗");strcpy(s01->sex, "男");s01->age = 18;Stu *s02 = calloc(1,sizeof(Stu));strcpy(s02->name, "李槐");strcpy(s02->sex, "男");s02->age = 8;Stu *s03 = calloc(1,sizeof(Stu));strcpy(s03->name, "李寶瓶");strcpy(s03->sex, "女");s03->age = 14;Stu *s04 = calloc(1,sizeof(Stu));strcpy(s04->name, "裴錢");strcpy(s04->sex, "女");s04->age = 12;Stu *s05 = calloc(1,sizeof(Stu));strcpy(s05->name, "崔東山");strcpy(s05->sex, "男");s05->age = 16;Stu *head = s01; //將s01作為首節點s01->next = s02; //將s02設置為s01的下一個節點 s02->next = s03;s03->next = s04;s04->next = s05;//鏈表的遍歷//pd:當前鏈表的節點Stu *pd = head;while(pd != NULL){printf("%s\t%s\t%d\n", pd->name, pd->sex, pd->age);//下一個節點賦值給當前節點,為下一輪循環pd = pd->next;}return 0;
}
// 陳晴朗 男 18
// 李槐 男 8
// 李寶瓶 女 14
// 裴錢 女 12
// 崔東山 男 16
練習:學員管理系統
需求:
選項有:1,查詢所有學員信息2,添加學員信息3,插入學員信息4,刪除學員信息5,修改學員信息(作業)6,查找指定位置的學員(作業)7,退出程序(釋放內存)
代碼:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct student
{//數據域char name[30];char sex[10];int num;//指針域struct student *next;
}STU;
//記錄鏈表首節點
STU *head = NULL;//查詢函數(打印鏈表)
void print_link(STU *head)
{//定義一個節點作為當前節點STU *pd = head;while (pd != NULL){printf("姓名:%s\t性別:%s\t學號:%d\n",pd->name,pd->sex,pd->num);//獲取下一個節點賦值給當前節點pd = pd->next;}printf("\n");
}//計算鏈表長度
int get_len(STU *head)
{int i = 0;STU *pd = head;while(pd != NULL){i++;pd = pd->next;}return i;
}//添加學員信息邏輯
/*添加新節點到連接尾部參數;head:鏈表的頭節點stu:要添加的新節點返回值鏈表的頭節點
*/
STU *add(STU *head, STU *stu)
{//如果傳進來的學員信息為空,直接返回傳進來的頭結點if (stu == NULL){return head;}//判斷鏈表首節點是否為空,為空表示此時鏈表還沒有節點,直接將數據賦值給首結點if (head == NULL){head = stu;printf("添加成功\n\n");return head;}//查詢最后一個節點,找到NULL的前一個節點//假設當前節點就是最后一個節點(即一個也沒有),此時首節點就是最后一個節點STU *lastNode = head;while(lastNode != NULL){//進循環,表示這不是最后一個節點,就判斷他的下一個節點是否為空,為空直接跳出循環if (lastNode->next == NULL){break;}else{//此時表示他的下一個節點不是NULL,將它的下一個節點賦值給它lastNode = lastNode->next;}}//沒有進循環表示lastNode就是當前鏈表的最后一個節點//此時就要將本次創建的節點添加到 原鏈表最后一個節點的后面lastNode->next = stu;printf("添加成功\n\n");return head;
}//尾部添加學員信息
STU *add_student(STU *head)
{//開辟一塊堆內存空間賦值 結構體指針變量,用來存儲學員信息(即stu指向這片堆內存)STU *stu = calloc(1,sizeof(STU));printf("請輸入學員姓名\n");scanf("%s", stu->name);printf("請輸入學員性別\n");scanf("%s", stu->sex);printf("請輸入學員學號\n");scanf("%d", &stu->num);head = add(head, stu);return head;}//插入學員
STU *inster_student(STU *head)
{STU *stu = calloc(1,sizeof(STU));printf("請輸入學員姓名\n");scanf("%s", stu->name);printf("請輸入學員性別\n");scanf("%s", stu->sex);printf("請輸入學員學號\n");scanf("%d", &stu->num);printf("請輸入要插入學員的位置(從0開始)\n");int index = 0;scanf("%d", &index);//排除錯誤int len = get_len(head);if (index > len){//插入位置超過鏈表長度,插入鏈表末位head = add(head, stu);return head;}if (index < 0){printf("輸入位置有誤\n");return head;}//為0表示插入第一個位置if (index == 0){//將首節點位置變為下一個節點stu->next = head;//將新建的節點賦值給首節點head = stu;printf("添加成功\n");return head;}//尋找插入節點的前一個節點STU *pd = head;for (int i = 0; i < index - 1; i++){pd = pd->next;}stu->next = pd->next; //將前一個節點的原后一個節點賦值給新節點的下一個節點pd->next = stu;printf("添加成功\n\n");return head;
}//刪除學員
STU *del_student(STU *head)
{printf("請輸入要刪除學員的位置(從0開始)\n");int index = 0;scanf("%d", &index);//排除錯誤int len = get_len(head);if (index > len || index < 0){printf("輸入位置有誤\n");return head;}//為0表示刪除第一個位置if (index == 0){//將首節點的下一個節點變為首節點head = head->next;printf("刪除成功\n");return head;}STU *pd1 = head, *pd2;int i = 0;while (i < index){pd2 = pd1;pd1 = pd1->next;i++;}if (pd1 != NULL){pd2->next = pd1->next;}printf("刪除成功\n");return head;
}//修改學員
STU *update_student(STU *head)
{STU *stu = calloc(1,sizeof(STU));printf("請輸入要修改學員姓名\n");scanf("%s", stu->name);printf("請輸入要修改學員性別\n");scanf("%s", stu->sex);printf("請輸入要修改學員學號\n");scanf("%d", &stu->num);printf("請輸入要修改學員的位置(從0開始)\n");int index = 0;scanf("%d", &index);//排除錯誤int len = get_len(head);if (index > len || index < 0){printf("輸入位置有誤\n");return head;}//為0表示修改第一個位置if (index == 0){//將新節點的next指向原首節點的下一個節點stu->next = head->next;printf("修改成功\n");return head;}//不為0int i = 0;//定義兩個指針變量記錄當前節點和上一個節點STU *pd1 = head, *pd2;while (i < index){pd2 = pd1;pd1 = pd1->next;i++;}pd2->next = stu;stu->next = pd1->next;printf("修改成功\n");return head;
}//查詢指定學員位置
STU *find_student(STU *head)
{printf("請輸入要查找學員的位置(從0開始)\n");int index = 0;scanf("%d", &index);//排除錯誤int len = get_len(head);if (index > len || index < 0){printf("輸入位置有誤\n");return head;}STU *pd = head, *pd1;//為0表示查找的是第一個學員if (index == 0){//直接打印首節點printf("姓名:%s\t性別:%s\t學號:%d\n\n",pd->name,pd->sex,pd->num);return head;}//不為0,尋找當前節點int i = 0;while (i < index){pd1 = pd;pd = pd->next;i++;}printf("姓名:%s\t性別:%s\t學號:%d\n\n",pd->name,pd->sex,pd->num);return head;
}//菜單函數
void my_menu(int tag)
{switch (tag){case 1:print_link(head);break;case 2:head = add_student(head);break;case 3:head = inster_student(head);break;case 4:head = del_student(head);break;case 5:head = update_student(head);break;case 6:head = find_student(head);break;default:printf("輸入有誤, 請重新輸入\n\n");break;}
}//釋放內存
void free_link(STU *head)
{STU *pd = head;while (pd != NULL){//記錄其下一個節點STU *next = pd->next;//釋放當前節點free(pd);//更換當前節點pd = next;}}int main(int argc, char const *argv[])
{while (1){printf("1,查詢所有學員信息\n2,添加學員信息\n3,插入學員信息\n4,刪除學員信息\n5,修改學員信息\n6,查找指定位置的學員\n7,退出程序\n\n");printf("請輸入本次操作的選項(輸入對應數字)\n");int tag = 0;scanf("%d", &tag);if (tag != 7){my_menu(tag);}else{free_link(head);printf("歡迎下次光臨!\n");break;}}return 0;
}