bilibiliclass22-28_資料結構與演算法_線性表的鏈式表示和實現
技術標籤:資料結構與演算法_嗶哩嗶哩課堂筆記
知識回顧
順序表的特點:以物理位置相鄰表示邏輯關係。
順序表的優點:任一元素均可隨機存取。
順序表的缺點:進行插入和刪除操作時,需移動大量的元素。儲存空間不靈活
鏈式儲存結構
結點在儲存器中的位置是任意的,即邏輯上相鄰的資料元素在物理上不一定相鄰
這組儲存單元既可以是連續的,也可以是不連續的,甚至是零散分佈在記憶體中的任意位置上的。
例子1
線性表:(趙,錢,孫,李,周,吳,鄭,王)
例子2
例:26個英文小寫字母表的鏈式儲存結構
邏輯結構:( a, b,... ,y,z)
與鏈式儲存有關的術語
1、結點:資料元素的儲存映象。由資料域和指標域兩部分組成
資料域:儲存元素數值資料
指標域:儲存直接後繼結點的儲存位置
2、連結串列:n個結點由指標鏈組成一個連結串列。
單鏈表、雙鏈表、迴圈連結串列:
結點只有一個指標域的連結串列,稱為單鏈表或線性連結串列
單鏈表是由頭指標唯一確定,因此單鏈表可以用頭指標的名字來命名。
結點有兩個指標域的連結串列,稱為L為雙鏈表
首尾相接的連結串列稱為迴圈連結串列
頭指標 頭結點 首元結點
頭指標:是指向連結串列中第一個結點的指標
首元結點:是指連結串列中儲存第一個資料元素a1的結點
頭結點:是在連結串列的首元結點之前附設的一個結點;
前面的例子中的連結串列的儲存結構示意圖有以下兩種形式:
①不帶頭結點
②帶頭結點
頭結點好處
1便於首元結點的處理
首元結點的地址儲存在頭結點的指標域中,所以在連結串列的第一個位置上的操作和其它位置一致,無須進行特殊處理;
2便於空表和非空表的統一處理
無論連結串列是否為空,頭指標都是指向頭結點的非空指標,因此空表和非空表的處理也就統一了。
3.頭結點的資料域可以為空,也可存放線性表長度等附加資訊,但此結點不能計入連結串列長度值
空表
無頭結點時,頭指標為空時表示空表
有頭結點時,當頭結點的指標域為空時表示空表
連結串列(鏈式儲存結構)的特點
(1)結點在儲存器中的位置是任意的,即邏輯上相鄰的資料元素在物理上不一定相鄰。
(2)訪問時只能通過頭指標進入連結串列,並通過每個結點的指標域依次向後順序掃描其餘結點,所以尋找第一個結點和最後一個結點所花費的時間不等
知識回顧
線性表的鏈式儲存結構
線性表中資料元素(結點)在儲存器中的位置是任意的,即邏輯上相鄰的資料元素在物理位置上不一定相鄰。
結點
資料│指標
連結串列 n個結點由指標鏈組成一個連結串列。連結串列是順序存取的。
單鏈表:每個結點只有一個指標域
雙鏈表:每個結點有兩個指標域
迴圈連結串列:連結串列結點首尾相接
單鏈表基本操作的實現
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
//連結串列的資料域
struct student
{
char name[20];
int num;
};
//連結串列的樣子
struct Node {
struct student data;
struct Node* next;
};
//建立表頭,即單鏈表的初始化
struct Node* creatList()
{
struct Node* headNode = (struct Node*)malloc(sizeof(struct Node));
//headNode 成為了結構體變數
//headNode->next=1;
headNode->next = NULL;
return headNode;
}
//建立節點
struct Node* creatNode(struct student data)
{
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = NULL;
return newNode;
}
//列印節點,遍歷節點
void printList(struct Node* headNode)
{
struct Node* pMove = headNode->next;
printf("name\tnum\n");
while (pMove)
{
printf("%s\t%d\n",pMove->data.name, pMove->data.num);
pMove = pMove->next;
}
printf("\n");
}
//表頭法插入
void insertNodeByHead(struct Node* headNode, struct student data)
{
//1.建立插入的結點
struct Node* newNode = creatNode(data);
newNode->next = headNode->next;
headNode->next = newNode;
}
//連結串列的刪除:指定位置的刪除
void deleteNodeByAppoinNum(struct Node* headNode, int num)
{
struct Node* posNode = headNode->next;
struct Node* posNodeFront = headNode;
if (posNode == NULL)
printf("無法刪除,連結串列為空\n");
else
{
while (posNode->data.num != num)
{
posNodeFront = posNode;
posNode = posNodeFront->next;
if (posNode == NULL)
{
printf("沒有找到相關資訊,無法刪除\n");
return;
}
}
posNodeFront->next = posNode->next;
free(posNode);
}
}
//判斷連結串列是否為空
//空表:連結串列中無元素,稱為空連結串列(頭指標和頭結點仍然在)
//若L為空表,則返回1,否則返回0
int ListEmpty(struct Node* list)
{
if (list->next)//非空
return 0;
else
return 1;
}
//銷燬單鏈表
void DestroyList_L(struct Node* list)
{
struct Node* p;
while (list)
{
p = list;
list = list->next;
free(p);
}
return 1;
}
//清空連結串列:連結串列-->空表
void ClearList(struct Node* list)
{
struct Node* p,*q;
p = list->next;
while (p)//沒有到表尾
{
q = p->next;
free(p);
p = q;
}
//頭指標設定為空
list->next = NULL;
return 1;
}
//求單鏈表的表長
int countList(struct Node* list)
{
struct Node* p = list->next;//p指向第一個節點
int count = 0;
while (p!=NULL)//遍歷
{
p = p->next;
count++;
}
return count;
}
int main()
{
struct Node* list = creatList();
struct student info;
while (1)
{
printf("請輸入學生的姓名 學號:>");
setbuf(stdin, NULL);
scanf("%s%d",&info.name,&info.num);
insertNodeByHead(list,info);
printf("continue(Y/N)");
setbuf(stdin,NULL);
int choice = getchar();
if (choice == 'N' || choice == 'n')
{
break;
}
}
printList(list);
printf("請輸入要刪除學生的學號:>");
scanf("%d", &info.num);
deleteNodeByAppoinNum(list, info.num);
printList(list);
ClearList(list);
printList(list);
return 0;
}