在建設(shè)部網(wǎng)站上的舉報(bào)國(guó)外免費(fèi)輿情網(wǎng)站有哪些軟件
目錄
數(shù)據(jù)結(jié)構(gòu)之雙向鏈表::
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? List.h
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? List.c
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 1.創(chuàng)建返回鏈表的頭結(jié)點(diǎn)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 2.雙向鏈表初始化
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 3.雙向鏈表打印
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 4.雙向鏈表銷毀
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 5.雙向鏈表尾插
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 6.雙向鏈表尾刪
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 7.雙向鏈表頭插
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 8.雙向鏈表頭刪
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 9.雙向鏈表查找
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 10.雙向鏈表在pos前插入
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 11.雙向鏈表刪除pos位置
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 12.雙向鏈表判空
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 13.雙向鏈表長(zhǎng)度
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 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é)點(diǎn)
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.雙向鏈表銷毀
//可以傳二級(jí) 內(nèi)部置空頭結(jié)點(diǎn)
//建議:也可以考慮使用一級(jí)指針 讓調(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 取反為假就報(bào)錯(cuò)assert(!ListEmpty(phead));//刪掉最后一個(gè)結(jié)點(diǎn) 哨兵位變成自己指向自己 代碼依然成立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é)點(diǎn)之間的關(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 取反為假就報(bào)錯(cuò)assert(!ListEmpty(phead));//刪到剩最后一個(gè)結(jié)點(diǎn)時(shí) first指向最后一個(gè)結(jié)點(diǎn) second指向哨兵位結(jié)點(diǎn) 刪到最后哨兵位自己指向自己 代碼依然成立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.雙向鏈表長(zhǎng)度
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ū)別
不同點(diǎn) | 順序表 | 鏈表 |
存儲(chǔ)空間上 | 物理上一定連續(xù) | 邏輯上連續(xù)但是物理上不一定連續(xù) |
隨機(jī)訪問(wèn) | 支持O(1) | 不支持O(N) |
任意位置插入或者刪除元素 | 可能需要搬移元素,效率低O(N) | 只需修改指針指向 |
插入 | 動(dòng)態(tài)順序表,空間不夠時(shí)需要擴(kuò)容 | 沒(méi)有容量的概念 |
應(yīng)用場(chǎng)景 | 元素高效存儲(chǔ)+頻繁訪問(wèn) | 任意位置插入和刪除頻繁 |
緩存利用率 | 高 | 低 |
備注:緩存利用率參考存儲(chǔ)體系結(jié)構(gòu)以及局部原理性
順序表的優(yōu)點(diǎn):
1.尾插尾刪的效率很高
2.可以用下標(biāo)隨機(jī)訪問(wèn)
3.相比鏈表結(jié)構(gòu) CPU高速緩存命中率更高
順序表的缺點(diǎn):
1.頭部和中部插入效率低——O(N)
2.擴(kuò)容時(shí)的性能消耗+擴(kuò)容時(shí)的空間浪費(fèi)
鏈表的優(yōu)點(diǎn):
1.任意位置插入刪除效率很高——O(1)
2.按需申請(qǐng)釋放
鏈表的缺點(diǎn):
1.不支持隨機(jī)訪問(wèn)
注:三級(jí)緩存被稱為CPU周圍的禁衛(wèi)軍
CPU執(zhí)行指令不會(huì)直接訪問(wèn)內(nèi)存?
1.先看數(shù)據(jù)在不在三級(jí)緩存,在(命中),直接訪問(wèn)
2.不在(不命中),先加載到緩存,再訪問(wèn)
注:加載到緩存時(shí),會(huì)將需要加載的位置開(kāi)始的一段都加載進(jìn)緩存,(加載多少取決于硬件)
由于順序表的數(shù)據(jù)彼此之間的地址緊密聯(lián)系 所以加載到高速緩存時(shí)命中率高 但鏈表不然 更可能會(huì)導(dǎo)致緩存污染?
?