在建設(shè)部網(wǎng)站上的舉報國外免費輿情網(wǎng)站有哪些軟件
目錄
數(shù)據(jù)結(jié)構(gòu)之雙向鏈表::
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? List.h
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? List.c
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 1.創(chuàng)建返回鏈表的頭結(jié)點
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 2.雙向鏈表初始化
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 3.雙向鏈表打印
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 4.雙向鏈表銷毀
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 5.雙向鏈表尾插
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 6.雙向鏈表尾刪
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 7.雙向鏈表頭插
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 8.雙向鏈表頭刪
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 9.雙向鏈表查找
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 10.雙向鏈表在pos前插入
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 11.雙向鏈表刪除pos位置
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 12.雙向鏈表判空
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 13.雙向鏈表長度
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 14.順序表與鏈表的區(qū)別
數(shù)據(jù)結(jié)構(gòu)之雙向鏈表::
List.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int LTDataType;
typedef struct ListNode
{struct ListNode* next;struct ListNode* prev;LTDataType data;
}LTNode;
LTNode* ListInit();
void ListPrint(LTNode* phead);
void ListPushBack(LTNode* phead, LTDataType x);
void ListPushFront(LTNode* phead, LTDataType x);
void ListPopBack(LTNode* phead);
void ListPopFront(LTNode* phead);
bool ListEmpty(LTNode* phead);
size_t ListSize(LTNode* phead);
LTNode* ListFind(LTNode* phead, LTDataType x);
//在pos之前插入
void ListInsert(LTNode* pos, LTDataType x);
//刪除pos位置
void ListErase(LTNode* pos);
void ListDestory(LTNode* phead);
List.c
1.創(chuàng)建返回鏈表的頭結(jié)點
LTNode* BuyListNode(LTDataType x)
{LTNode* node = (LTNode*)malloc(sizeof(LTNode));if (node == NULL){perror("malloc fail");exit(-1);}node->next = NULL;node->prev = NULL;
}
2.雙向鏈表初始化
LTNode* ListInit()
{LTNode* guard = (LTNode*)malloc(sizeof(LTNode));if (guard == NULL){perror("malloc fail");exit(-1);}guard->next = guard;guard->prev = guard;return guard;
}
3.雙向鏈表打印
void ListPrint(LTNode* phead)
{assert(phead);printf("guard<=>");LTNode* cur = phead->next;while (cur != phead){printf("%d<=>", cur->data);cur = cur->next;}printf("\n");
}
4.雙向鏈表銷毀
//可以傳二級 內(nèi)部置空頭結(jié)點
//建議:也可以考慮使用一級指針 讓調(diào)用ListDestory的人將其置空 保持接口的一致性
void ListDestory(LTNode* phead)
{assert(phead);LTNode* cur = phead->next;while (cur != phead){LTNode* next = cur->next;free(cur);cur = next;}free(phead);//phead = NULL;
}
5.雙向鏈表尾插
void ListPushBack(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode = BuyListNode(x);LTNode* tail = phead->prev;tail->next = newnode;newnode->prev = tail;newnode->next = phead;phead->prev = newnode;
}
6.雙向鏈表尾刪
void ListPopBack(LTNode* phead)
{assert(phead);//鏈表為空返回true 取反為假就報錯assert(!ListEmpty(phead));//刪掉最后一個結(jié)點 哨兵位變成自己指向自己 代碼依然成立LTNode* tail = phead->prev;LTNode* prev = tail->prev;prev->next = phead;phead->prev = prev;free(tail);tail = NULL;
}
7.雙向鏈表頭插
void ListPushFront(LTNode* phead, LTDataType x)
{assert(phead);//先鏈接newnode和phead->next結(jié)點之間的關(guān)系/*LTNode* newnode = BuyListNode(x);newnode->next = phead->next;phead->next->prev = newnode;phead->next = newnode;newnode->prev = phead;*///不關(guān)心先后順序LTNode* newnode = BuyListNode(x);LTNode* first = phead->next;phead->next = newnode;newnode->prev = phead;newnode->next = first;first->prev = newnode;
}
8.雙向鏈表頭刪
void ListPopFront(LTNode* phead)
{assert(phead);//鏈表為空返回true 取反為假就報錯assert(!ListEmpty(phead));//刪到剩最后一個結(jié)點時 first指向最后一個結(jié)點 second指向哨兵位結(jié)點 刪到最后哨兵位自己指向自己 代碼依然成立LTNode* first = phead->next;LTNode* second = first->next;phead->next = second;second->prev = phead;free(first);first = NULL;
}
9.雙向鏈表查找
//雙向鏈表的查找可以替代其修改函數(shù)
LTNode* ListFind(LTNode* phead, LTDataType x)
{assert(phead);LTNode* cur = phead->next;while (cur != phead){if (cur->data == x){return cur;}cur = cur->next;}return NULL;
}
10.雙向鏈表在pos前插入
//在pos之前插入
void ListInsert(LTNode* pos, LTDataType x)
{assert(pos);LTNode* prev = pos->prev;LTNode* newnode = BuyListNode(x);//prev newnode posprev->next = newnode;newnode->prev = prev;newnode->next = pos;pos->prev = newnode;
}
//ListInsert(phead,x)代替尾插
//ListInsert(phead->next,x)代替頭插
11.雙向鏈表刪除pos位置
//刪除pos位置
void ListErase(LTNode* pos)
{assert(pos);LTNode* prev = pos->prev;LTNode* next = pos->next;prev->next = next;next->prev = prev;free(pos);//pos = NULL;置空并不起作用
}
//ListErase(phead->prev)代替尾刪
//ListErase(phead->next)代替頭刪
12.雙向鏈表判空
bool ListEmpty(LTNode* phead)
{assert(phead);return phead->next == phead;
}
13.雙向鏈表長度
size_t ListSize(LTNode* phead)
{assert(phead);size_t n = 0;LTNode* cur = phead->next;while (cur != phead){++n;cur = cur->next;}return n;
}
14.順序表與鏈表的區(qū)別
不同點 | 順序表 | 鏈表 |
存儲空間上 | 物理上一定連續(xù) | 邏輯上連續(xù)但是物理上不一定連續(xù) |
隨機訪問 | 支持O(1) | 不支持O(N) |
任意位置插入或者刪除元素 | 可能需要搬移元素,效率低O(N) | 只需修改指針指向 |
插入 | 動態(tài)順序表,空間不夠時需要擴容 | 沒有容量的概念 |
應(yīng)用場景 | 元素高效存儲+頻繁訪問 | 任意位置插入和刪除頻繁 |
緩存利用率 | 高 | 低 |
備注:緩存利用率參考存儲體系結(jié)構(gòu)以及局部原理性
順序表的優(yōu)點:
1.尾插尾刪的效率很高
2.可以用下標隨機訪問
3.相比鏈表結(jié)構(gòu) CPU高速緩存命中率更高
順序表的缺點:
1.頭部和中部插入效率低——O(N)
2.擴容時的性能消耗+擴容時的空間浪費
鏈表的優(yōu)點:
1.任意位置插入刪除效率很高——O(1)
2.按需申請釋放
鏈表的缺點:
1.不支持隨機訪問
注:三級緩存被稱為CPU周圍的禁衛(wèi)軍
CPU執(zhí)行指令不會直接訪問內(nèi)存?
1.先看數(shù)據(jù)在不在三級緩存,在(命中),直接訪問
2.不在(不命中),先加載到緩存,再訪問
注:加載到緩存時,會將需要加載的位置開始的一段都加載進緩存,(加載多少取決于硬件)
由于順序表的數(shù)據(jù)彼此之間的地址緊密聯(lián)系 所以加載到高速緩存時命中率高 但鏈表不然 更可能會導(dǎo)致緩存污染?
?