線性表是由n(n >= 0)個數據元素(結點)組成的有限序列.node
則n爲表的長度, 當n = 0時爲空表算法
L = (a1, a1, …, an)數組
其中a1爲起始結點, an爲終端結點. 對任意一對相鄰的結點ai和ai+1 (1 <= i < n), ai稱爲ai+1的直接前驅, ai+1稱爲ai的直接後繼.ui
在這張圖片中, 線性表是一個由10個結點組成的有限序列. 表的長度爲10, 結點A爲起始結點, 結點J爲終端結點. 對於任意相鄰的兩個結點, 例如AB兩個結點, 結點A爲結點B的直接前驅, 結點B爲結點A的直接後繼.spa
將表中的結點依次存放在計算機內存中一組連結的存儲單元中. 用順序存儲方式實現的線性表稱爲順序表. 通常使用數組來表示順序表.3d
已知a1地址爲locate(a1), 每一個數據佔m個存儲單元, 則ai的地址指針
locate(ai) = locate(a1) + m * (i - 1)code
線性表的大小: maxSizecdn
線性表的長度: lengthblog
所存放的數據類型: DataType
線性表的插入運算是指在表的第 i (1 <= i <= n+1) 個位置上, 插入一個新結點, 使長度爲n的線性表變成長度爲n + 1的線性表
前提: 線性表的長度爲n, 要插入的位置爲i
元素的移動次數: 在i位置插入數據時, 要移動 n - i + 1 個數據元素
平均移動元素個數: 咱們能夠簡單理解爲最好的時候, 在末尾插入, 移動0個數據元素, 最壞的時候, 在位置爲1的地插入, 移動n個數據元素, 則平均移動元素個數爲 n / 2, 則時間複雜度爲O(n)
注意事項
1. 當表空間已滿, 不可再作插入操做
2. 當插入位置爲非法位置, 不可作正常插入操做
複製代碼
代碼
/** 線性表的插入 @param pList 類型爲SeqList的結構體指針 @param x 要插入的類型爲DataType類型的數據元素 @param i 要插入的位置 */
void insertSeqList(SeqList * pList, DataType x, int i) {
// 判斷線性表是否已滿
if (pList->length == maxSize) {
printf("表已滿 \n");
return;
}
// 檢查插入位置是否合法
if (i < 1 || i > (pList->length) + 1) {
printf("插入位置不合法 \n");
return;
}
// 進行插入操做
// 從表的最後一個位置依次進行後移
for (int j = pList->length; j >= i; j--) {
pList->data[j] = pList->data[j-1];
}
// 後移完成以後, 對空出的位置進行賦值
pList->data[i - 1] = x;
// 表的長度加1
pList->length++;
}
複製代碼
線性表的刪除運算是指將表的第 i 個結點刪去, 使長度爲 n 的線性表變成長度爲 n-1 的線性表
注意事項
代碼
/** 線性表的刪除 @param pList 類型爲SeqList結構體的指針 @param i 要刪除的位置 */
void deleteSeqList(SeqList * pList, int i) {
// 檢查刪除位置是否合法
if (i < 1 || i > pList -> length) {
printf("刪除位置不合法");
return;
}
// 進行刪除操做, 依次左移
for (int j = i; j < pList->length; j++) {
pList->data[j - 1] = pList->data[j];
}
// 表的長度減1
pList->length--;
}
複製代碼
元素的移動次數: 在i位置刪除數據時, 要移動 n - i 個數據元素
平均移動元素個數: 咱們能夠簡單理解爲最好的時候, 在末尾刪除, 移動0個數據元素, 最壞的時候, 在位置爲1的地刪除, 移動 n-1 個數據元素, 則平均移動元素個數爲 (n-1) / 2, 則時間複雜度爲O(n)
定位運算的功能是求L中值等於x的結點序號的最小值, 當不存在這種結點時結果爲0
/** 線性表的定位 @param pList 類型爲SeqList結構體的指針 @param name 要查找的姓名 @return 查找到的元素的位置 */
int locateSeqList(SeqList * pList, char name[]) {
int i = 0;
// 在順序表中查找值爲name的結點
while (i < pList->length && pList->data[i].name == name) {
i++;
}
// 若找到值爲name的結點, 則返回結點的序號
if (i < pList->length) {
return i + 1;
} else { // 未找到值爲name的結點, 返回0
return 0;
}
}
複製代碼
連接方式存儲的線性表稱爲鏈表. Link List
{% asset_img node.png %}
數據域, 又爲data域, 存放結點中的數據
指針域, 又爲next域, 存放結點的直接後繼的地址
全部結點經過指針連接而組成單鏈表.
NULL稱爲爲空指針
Head稱爲頭指針, 存放鏈表中的第一個結點的地址
單鏈表中第一個結點內通常不存數據, 稱爲爲頭結點
// 聲明一個結構體類型
typedef struct {
char name[12];
int age;
} DataType;
// 聲明一個單鏈表類型
typedef struct node {
DataType data; // 數據域
struct node * next; // 指針域
} Node, * LinkList;
/** 初始化一個單鏈表 @return 初始化好的單鏈表 */
LinkList initiateLinkList() {
// 頭指針
LinkList head;
// 動態建立一個結點, 也就是頭結點, 而後讓頭指針指向這個結點
head = malloc(sizeof(Node));
// 頭結點的指針域爲NULL
head->next = NULL;
// 返回這個單鏈表
return head;
}
複製代碼
插入運算是將值爲x的新結點 插入到表的第i個結點的位置上, 即插入到ai-1與ai之間
/** 插入 @param list 單鏈表 @param x 要插入的數據元素 @param i 要插入的位置 */
void insertLinkList(LinkList list, DataType x, int i) {
LinkList s, p;
if (i == 1) {
p = list;
} else {
// 找到第 i-1 個數據元素結點
p = getLinkList(list, i - 1);
}
if (p == NULL) {
// 若是不存在, 返回錯誤信息
printf("找不到插入的位置");
} else{
// 生成新結點並初始化
s = malloc(sizeof(Node));
s->data = x;
// 新結點的指針域指向第i個元素
s->next = p->next;
// 第 i-1 個結點的指針域指向新結點
p->next = s;
}
}
複製代碼
在單鏈表中刪除第i個結點的基本操做爲: 找到線性表中第i-1個結點, 修改其指向直接後繼的指針
/** 刪除 @param list 單鏈表 @param i 要刪除結點的位置 */
void deleteLinkList(LinkList list, int i) {
LinkList p;
// 找到待刪結點的直接前驅
if (i == 1) {
p = list;
} else {
p = getLinkList(list, i-1);
}
// 若直接前驅存在, 且待刪結點存在
if (p != NULL && p->next != NULL) {
// q指向待刪結點
LinkList q = p->next;
// 移出待刪結點
p->next = q->next;
// 釋放已經移出的結點
free(q);
} else {
printf("要不到要刪除的結點");
}
}
複製代碼
在單鏈表存儲結構中, 線性表的長度等於單鏈表所含結點的個數(不含頭結點)
/** 求表的長度 @param list 單鏈表 @return 表的長度 */
int LengthLinkList(LinkList list) {
// 用於計數
int j = 0;
// p指向頭指針
LinkList p = list;
// 當下一個結點不爲空時, 計數加1, p指向下一個結點
while (p->next != NULL) {
j++;
p = p->next;
}
// 返回表的長度
return j;
}
複製代碼
/** 讀表元素 @param list 單鏈表 @param i 要讀取的位置 @return 若是有返回讀取到的元素, 沒有則返回NULL */
LinkList getLinkList(LinkList list, int i) {
// 用於計數
int j = 1;
// p指向首結點
LinkList p = list->next;
while (j < i && p != NULL) {
j++;
p = p->next;
}
// 若是j等於i, 則p指向的結點爲要找的結點
if (j == i) {
return p;
} else { // 不然沒有要找的結點
return NULL;
}
}
複製代碼
定位運算是給定表元素的值, 找出這個元素的位置
/** 定位 @param list 單鏈表 @param name 要查找的結點的名字 @return 若是查找到了, 則返回結點的位置, 若是沒有, 則返回0 */
int locateLinkList(LinkList list, char name[]) {
int j = 0;
// p指向首結點
LinkList p = list->next;
// 查找結點
while (p != NULL && !(strcmp(p->data.name, name) == 0)) {
j++;
p = p->next;
}
// 若是有則返回序號, 沒有返回0
if (p != NULL) {
return j + 1;
} else {
return 0;
}
}
複製代碼
普通鏈表的終端結點的next值爲NULL
循環鏈表的終端結點的next指向頭結點
在循環鏈表中, 從任一結點出發都能掃描整個鏈表
在鏈表中設置兩個指針域, 一個指向後繼結點, 一個指向前驅結點, 這就是雙向鏈表
空雙向循環鏈表
非空雙向循環鏈表
設p指向待刪結點, 刪除*p可這樣作
p -> prior -> next = p -> next; // p前驅結點的直接後繼指向p的後繼結點
p -> next -> prior = p -> prior; // p後繼結點的直接前驅指向p的前驅結點
free(p); // 釋放*p的空間
在p所指後面插入一個新的結點t, 插入可這樣作
t -> next = p -> next;
t -> prior = p;
p -> next -> prior = t;
p -> next = t;
#include <stdio.h>
// 定義一個結構體類型
typedef struct {
char name[10];
int age;
} DataType;
// 順序表的結構體定義
// 線性表的大小, 也就是最多存儲多少個數據元素
const int maxSize = 100;
typedef struct {
// 所存放的數據類型爲int, 最多存放100個元素的數組
DataType data[maxSize];
// 當前所存放的數據元素的個數
int length;
} SeqList;
/** 線性表的插入 @param pList 類型爲SeqList的結構體指針 @param x 要插入的類型爲DataType類型的數據元素 @param i 要插入的位置 */
void insertSeqList(SeqList * pList, DataType x, int i) {
// 判斷線性表是否已滿
if (pList->length == maxSize) {
printf("表已滿 \n");
return;
}
// 檢查插入位置是否合法
if (i < 1 || i > (pList->length) + 1) {
printf("插入位置不合法 \n");
return;
}
// 進行插入操做
// 從表的最後一個位置依次進行後移
for (int j = pList->length; j >= i; j--) {
pList->data[j] = pList->data[j-1];
}
// 後移完成以後, 對空出的位置進行賦值
pList->data[i - 1] = x;
// 表的長度加1
pList->length++;
}
/** 線性表的刪除 @param pList 類型爲SeqList結構體的指針 @param i 要刪除的位置 */
void deleteSeqList(SeqList * pList, int i) {
// 檢查刪除位置是否合法
if (i < 1 || i > pList -> length) {
printf("刪除位置不合法");
return;
}
// 進行刪除操做, 依次左移
for (int j = i; j < pList->length; j++) {
pList->data[j - 1] = pList->data[j];
}
// 表的長度減1
pList->length--;
}
/** 線性表的定位 @param pList 類型爲SeqList結構體的指針 @param name 要查找的姓名 @return 查找到的元素的位置 */
int locateSeqList(SeqList * pList, char name[]) {
int i = 0;
// 在順序表中查找值爲name的結點
while (i < pList->length && pList->data[i].name == name) {
i++;
}
// 若找到值爲name的結點, 則返回結點的序號
if (i < pList->length) {
return i + 1;
} else { // 未找到值爲name的結點, 返回0
return 0;
}
}
int main(int argc, const char * argv[]) {
// insert code here...
// 建立一個結構體實例, 並進行初始化
DataType dt1 = {"alex", 18};
DataType dt2 = {"kevin", 16};
DataType dt3 = {"jack", 21};
// 建立一個空的線性表
SeqList list = {};
// 建立一個指針指向這個線性表
SeqList * pList = &list;
printf("插入前表的長度: %d \n", list.length);
// 插入操做
insertSeqList(pList, dt1, 1);
insertSeqList(pList, dt2, 1);
insertSeqList(pList, dt3, 1);
printf("插入後表的長度: %d \n", list.length);
// 刪除操做
deleteSeqList(pList, 2);
printf("插入後表的長度: %d \n", list.length);
// 定位
int loc = locateSeqList(pList, "alex");
printf("alex在第%d位 \n", loc);
return 0;
}
複製代碼
#include <stdio.h>
#include <stdlib.h>
// 聲明一個結構體類型
typedef struct {
char name[12];
int age;
} DataType;
// 聲明一個單鏈表類型
typedef struct node {
DataType data; // 數據域
struct node * next; // 指針域
} Node, * LinkList;
/** 初始化一個單鏈表 @return 初始化好的單鏈表 */
LinkList initiateLinkList() {
// 頭指針
LinkList head;
// 動態建立一個結點, 也就是頭結點, 而後讓頭指針指向這個結點
head = malloc(sizeof(Node));
// 頭結點的指針域爲NULL
head->next = NULL;
// 返回這個單鏈表
return head;
}
/** 求表的長度 @param list 單鏈表 @return 表的長度 */
int LengthLinkList(LinkList list) {
// 用於計數
int j = 0;
// p指向頭指針
LinkList p = list;
// 當下一個結點不爲空時, 計數加1, p指向下一個結點
while (p->next != NULL) {
j++;
p = p->next;
}
// 返回表的長度
return j;
}
/** 讀表元素 @param list 單鏈表 @param i 要讀取的位置 @return 若是有返回讀取到的元素, 沒有則返回NULL */
LinkList getLinkList(LinkList list, int i) {
// 用於計數
int j = 1;
// p指向首結點
LinkList p = list->next;
while (j < i && p != NULL) {
j++;
p = p->next;
}
// 若是j等於i, 則p指向的結點爲要找的結點
if (j == i) {
return p;
} else { // 不然沒有要找的結點
return NULL;
}
}
/** 插入 @param list 單鏈表 @param x 要插入的數據元素 @param i 要插入的位置 */
void insertLinkList(LinkList list, DataType x, int i) {
LinkList s, p;
if (i == 1) {
p = list;
} else {
// 找到第 i-1 個數據元素結點
p = getLinkList(list, i - 1);
}
if (p == NULL) {
// 若是不存在, 返回錯誤信息
printf("找不到插入的位置");
} else{
// 生成新結點並初始化
s = malloc(sizeof(Node));
s->data = x;
// 新結點的指針域指向第i個元素
s->next = p->next;
// 第 i-1 個結點的指針域指向新結點
p->next = s;
}
}
/** 刪除 @param list 單鏈表 @param i 要刪除結點的位置 */
void deleteLinkList(LinkList list, int i) {
LinkList p;
// 找到待刪結點的直接前驅
if (i == 1) {
p = list;
} else {
p = getLinkList(list, i-1);
}
// 若直接前驅存在, 且待刪結點存在
if (p != NULL && p->next != NULL) {
// q指向待刪結點
LinkList q = p->next;
// 移出待刪結點
p->next = q->next;
// 釋放已經移出的結點
free(q);
} else {
printf("要不到要刪除的結點");
}
}
/** 定位 @param list 單鏈表 @param name 要查找的結點的名字 @return 若是查找到了, 則返回結點的位置, 若是沒有, 則返回0 */
int locateLinkList(LinkList list, char name[]) {
int j = 0;
// p指向首結點
LinkList p = list->next;
// 查找結點
while (p != NULL && !(strcmp(p->data.name, name) == 0)) {
j++;
p = p->next;
}
// 若是有則返回序號, 沒有返回0
if (p != NULL) {
return j + 1;
} else {
return 0;
}
}
int main(int argc, const char * argv[]) {
// insert code here...
Node list = {};
LinkList pList = &list;
DataType dt1 = {"jack", 18};
DataType dt2 = {"kevin", 20};
// 插入元素
insertLinkList(pList, dt1, 1);
insertLinkList(pList, dt2, 1);
// 讀表元素
LinkList p = getLinkList(pList, 2);
printf("%s \n", p->data.name);
// 刪除元素
// deleteLinkList(pList, 2);
// deleteLinkList(pList, 1);
// 讀表長
int length = LengthLinkList(pList);
printf("表的長度爲: %d \n", length);
// 定位
int loc = locateLinkList(pList, "kevin");
printf("在第%d位 \n", loc);
return 0;
}
複製代碼