一、預備知識:typedef
基本使用
#include <stdio.h>
typedef int AAA; // 為int再重新取一個名字,AAA就等於int
typedef struct Student
{
int sid;
char name[100];
char sex;
}ST;
int main(void)
{
int i = 10; // 等價於 AAA = 10;
struct Student st; // 等價於 ST st;
struct Student * ps = &st; // 等價於 ST * ps = &st;
ST st2;
st2.sid = 10;
printf("%d \n", st2.sid);
return 0;
}
也可以這樣使用,這樣更加的方便
#include <stdio.h>
typedef struct Student
{
int sid;
char name[100];
char sex;
}* PST; // PST等價於 typedef struct *
int main(void)
{
struct Student st;
PST ps = &st;
ps->sid = 99;
printf("%d\n", ps->sid);
return 0;
}
還可以把上面的兩個結合起來
#include <stdio.h>
typedef struct Student
{
int sid;
char name[100];
char sex;
}* PST , STU; // PST等價於 typedef struct * , STU代表了typedef struct
int main(void)
{
STU st; // 等價於struct Student st
PST ps = &st;
ps->sid = 99;
printf("%d\n", ps->sid);
return 0;
}
二、離散存儲(鏈表)
定義:n個節點離散分配,彼此通過指針相連,每一個節點只有一個前驅節點和一個后續節點,首節點沒有前驅節點,尾節點沒有后續節點
專業術語:
- 首節點:第一個有效節點
- 尾節點:最后一個有效節點
- 頭節點:首節點前面
- 頭指針:指向頭節點的指針變量
- 尾指針:指向尾節點的指針變量
注意:頭節點的數據類型和首節點類型一樣,頭節點里面沒有存放有效數據,沒有實際含義,為了方便對鏈表的操作
如果通過希望一個函數來對鏈表進行處理,我們至少需要接收鏈表的那些參數
只需要一個參數:頭指針
因為我們可以通過頭指針推算出鏈表的其他所有參數
每一個鏈表節點的數據類型如何表示
#include <stdio.h>
typedef struct Node
{
int data; // 數據域
struct Node * pNext; // 指針域 指向了和它本身類型一樣的另外一個節點
}NODE , *PNODE;
// NODE 等價於struct Node
// PNODE 等價於struct Node *
int main(void)
{
return 0;
}
分類:
- 單鏈表
- 雙鏈表:每一個節點有兩個指針域
- 循環鏈表:能通任何一個節點找到其他所有的節點
- 非循環鏈表
算法:
- 遍歷
- 查找
- 清空
- 銷毀
- 求長度
- 排序
- 刪除節點
- 插入節點
算法
狹義的算法是與數據的存儲方式密切相關
廣義的算法與數據的存儲方式無關
泛型
利用某種技術達到的效果就是:不同的存儲方式,執行的操作是一樣的
多敲代碼,熟練的掌握,並進行改進
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct Node
{
int data;
struct Node * pNext;
}NODE , *PNODE; // NODE等價於struct Node , PNODE等價於struct Node *
PNODE create_list(void);
void traverse_list(PNODE pHead);
bool is_empty(PNODE pHead);
int length_list(PNODE pHead);
bool insert_list(PNODE , int ,int); // 第二個是插入位置,第三個是插入的值
bool delete(PNODE , int, int*); // 第二個是刪除的位置,第三個是所刪除位置的值
void sort_list(PNODE pHead);
int main(void)
{
PNODE pHead = NULL; // 等價於struct Node * pHead = NULL;
pHead = create_list(); // 創建一個非循環單鏈表,並將該鏈表的頭節點地址付給pHead
// if(is_empty(pHead))
// printf("鏈表為空\n");
// else
// printf("鏈表不為空\n");
// printf("鏈表的長度為%d\n", length_list(pHead) );
// sort_list(pHead);
insert_list(pHead , 4, 99);
int val;
if(delete(pHead, 1 , &val))
{
printf("刪除成功,你刪除的是%d\n", val);
}
else
{
printf("刪除失敗\n");
}
traverse_list(pHead);
return 0;
}
// 構建一個鏈表,並把頭節點地址值返回
PNODE create_list(void)
{
int len;
int i;
int val; // 用來臨時存放用戶輸入的節點的值
// 分配了一個不存放數據的頭結點
PNODE pHead = (PNODE)malloc(sizeof(NODE));
if (pHead == NULL)
{
printf("分配失敗,程序終止!\n");
exit(-1);
}
// pTail始終執行的都是尾結點
PNODE pTail = pHead;
pTail->pNext = NULL;
printf("請輸入你需要生成的鏈表節點的個數:\n");
scanf("%d" , &len);
for (i = 0; i < len; ++i)
{
printf("請輸入第%d個節點的值:", i+1);
scanf("%d" , &val);
PNODE pNew = (PNODE)malloc(sizeof(NODE));
if (pNew == NULL)
{
printf("分配失敗,程序終止!\n");
exit(-1);
}
pNew->data = val;
pTail->pNext = pNew;
pNew->pNext = NULL;
pTail = pNew;
}
return pHead;
}
// 進行遍歷
void traverse_list(PNODE pHead)
{
// 自定義一個指針用於遍歷
PNODE p = pHead->pNext;
while(p != NULL){
printf("%d ",p->data );
p = p->pNext;
}
return;
}
// 判斷鏈表是否為空
bool is_empty(PNODE pHead)
{
if (pHead->pNext == NULL)
return true;
else
return false;
}
// 鏈表的長度
int length_list(PNODE pHead)
{
// 自定義一個指針用於計算鏈表的長度
PNODE p = pHead->pNext;
int len = 0;
while(NULL != p)
{
++len;
p = p->pNext;
}
return len;
}
// 進行排序
void sort_list(PNODE pHead)
{
// 這里和數組的排序差不多,思想是一樣的
int i , j , t;
PNODE p , q;
int len = length_list(pHead);
for (i = 0 , p = pHead->pNext; i < len -1; ++i , p = p->pNext)
{
for (j = i+1 , q = p->pNext; j < len; ++j , q = q->pNext)
{
if (p->data > q->data)
{
t = p->data;
p->data = q->data;
q->data = t;
}
}
}
return;
}
// 插入操作
// 在pHead所指向鏈表的第pos個節點的前面插入一個新的結點,該結點的值是val,pos從1開始
bool insert_list(PNODE pHead, int pos , int val)
{
int i = 0;
PNODE p = pHead;
while(NULL != p && i < pos-1)
{
p = p->pNext;
++i;
}
if (i > pos-1 || NULL == p)
return false;
PNODE pNew = (PNODE)malloc(sizeof(NODE));
if (NULL == pNew)
{
printf("動態分配內存失敗\n");
exit(-1);
}
pNew->data = val;
PNODE q = p->pNext;
p->pNext = pNew;
pNew->pNext = q;
return true;
}
// 刪除操作
bool delete(PNODE pHead , int pos, int * pval)
{
int i = 0;
PNODE p = pHead;
while(NULL != p->pNext && i < pos-1)
{
p = p->pNext;
++i;
}
if (i > pos-1 || NULL == p->pNext)
return false;
PNODE q = p->pNext;
*pval = q->data;
// 刪除p結點后面的結點
p->pNext = p->pNext->pNext;
free(q);
q = NULL;
return true;
}