日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

第三个一千行+500行总结-数据结构C复习--知识点总结3--七到九章

發(fā)布時(shí)間:2023/12/4 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 第三个一千行+500行总结-数据结构C复习--知识点总结3--七到九章 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

第七章 (接知識(shí)點(diǎn)總結(jié)2) 圖

圖的遍歷:

//深度優(yōu)先搜索
#define OK 1
#define True ?1
#define Error -1
#define False 0
typedef enum{DG, DN, UDG. UDN}Graph;

int visited[MAX];
//Graph代表圖的一種存儲(chǔ)結(jié)構(gòu)比如鄰接表,鄰接矩陣?
void TranverseGraph(Graph g){
?? ?int vi;
?? ?
?? ?for(vi = 0; vi < g.vernum; vi++)?
?? ??? ?visited[vi] = False;
?? ?for(vi = 0; vi < g.vernum; vi++){//連通圖那么此操作執(zhí)行一次?
?? ??? ?if(!visited[vi])
?? ??? ??? ?DepthFirstSearch(g, vi);?? ?
?? ?}
}?
void DepthFirstSearch(Graph g, int v0)
{
?? ?visit(v0);
?? ?visited[v0] = True;
?? ?
?? ?w = FirstAdjVertex(g, v0);
?? ?while(w != -1){
?? ??? ?if(visited[w])
?? ??? ??? ?DepthFirstSearch(g, w);
?? ??? ?w = NextAdjVertex(g, v0, w);
?? ?}
}?

深度遍歷總結(jié):總之就是一直找鄰接點(diǎn),找到一個(gè)那么找這個(gè)結(jié)點(diǎn)的下一個(gè)鄰接點(diǎn),找不到就換...

對(duì)于鄰接表:
void DepthFirstSearch(AdjList g, int v0){
?? ?visit(v0);
?? ?visited[v0] = True;//這里的True是宏定義,bool類型的為true
?? ?
?? ?ArcNode *p;
?? ?p = ?g.vertex[v0].firstarc;
?? ?while(p){
?? ??? ?if(!visited[p->adjvex])
?? ??? ??? ?DepthFirstSearch(g, p->adjvex);
?? ??? ?p = p->nextarc;
?? ?}
}?

圖的遍歷--廣度優(yōu)先搜索?
void BreadFirstSearch(Graph g int v0){
?? ?visit(v0);
?? ?visited[v0] = True;//標(biāo)志數(shù)組,證明該結(jié)點(diǎn)已經(jīng)訪問過?
?? ?
?? ?InitQueue(&Q);
?? ?EnterQueue(&Q, v0);
?? ?
?? ?while(!IsEmpty(Q)){
?? ??? ?DeleteQueue(&Q, &v);
?? ??? ?w = FirstAdjVertex(g, v);
?? ??? ?while(w != -1){
?? ??? ??? ?if(!visited[w]){
?? ??? ??? ??? ?visit(w);
?? ??? ??? ??? ?visited[w] = True;
?? ??? ??? ??? ?EnterQueue(&Q, w);
?? ??? ??? ?}
?? ??? ??? ?w = NextAdjVertex(g, v, w);
?? ??? ?}
?? ?}
}?

廣度遍歷總結(jié):就是一層一層的訪問,訪問完這一個(gè)結(jié)點(diǎn)衍生出去路徑為1的結(jié)點(diǎn),在走下一層...


圖的應(yīng)用

//求圖中兩個(gè)節(jié)點(diǎn)的簡(jiǎn)單路徑
int pre[];

void one_path(Graph *G, int u, int v)
{
?? ?//找到一條從u到v結(jié)點(diǎn)的簡(jiǎn)單路徑
?? ?int i;
?? ?pre = (int *)malloc(G->vexnum * sizeof(int));
?? ?for(i = 0; i < G->vernum; i++)
?? ??? ?pre[i] = -1;//未訪問標(biāo)志?
?? ?pre[u] = -2;//訪問了,無(wú)前驅(qū)?
?? ?DSF_path(G, u, v);
?? ?free(pre);?
}

int DSF_path(Graph *G, int u, int v){
?? ?int j;
?? ?for(j = FirstAdj(G, u); j >= 0; j = nextadj(G, u, j)){
?? ??? ?if(pre[j] == -1){
?? ??? ??? ?pre[j] = u;
?? ??? ??? ?if(j == v)
?? ??? ??? ?{
?? ??? ??? ??? ?print_path(pre, v);
?? ??? ??? ??? ?return 1;
?? ??? ??? ?}
?? ??? ??? ?else if(DFS_path(G, j, v))
?? ??? ??? ??? ?return 1;?
?? ??? ?}?? ?
?? ?}
?? ?return 0;
}?

生成樹:一個(gè)連通圖的生成樹是一個(gè)極小聯(lián)通子圖, 含有全部頂點(diǎn),只有構(gòu)成一棵樹的n-1條邊
最小生成樹:各邊代價(jià)之和最小的生成樹

Prime算法:
思想:點(diǎn)集分為兩個(gè)U,V-U, 分別(U)存樹上的結(jié)點(diǎn)和(V-U)去掉U中結(jié)點(diǎn)的剩余結(jié)點(diǎn);從V-U種選擇代價(jià)最小的邊
?? ?并入邊集,直到U=V.這一算法不會(huì)構(gòu)成回路, 因?yàn)椴⑷氲倪吺冀K是鄰接點(diǎn)分布在U和V-U中.
?? ??
//鄰接矩陣
#define MAXV ...
typedef struct{
?? ?int no;//頂點(diǎn)編號(hào)?
?? ?InfoType info;
}VertexType;
typedef struct{
?? ?int edges[MAXV][MAXV];//鄰接矩陣?
?? ?int n, e;//頂點(diǎn)數(shù)量, 邊數(shù)?
?? ?VertexType vexs[MAXV];//存放結(jié)點(diǎn)信息?
}MatGraph;?
#define M 32767
void Prime(MatGraph g, int v){
?? ?int lowcost[MAXV];
?? ?int min;
?? ?int closet[MAXV];
?? ?int i, j ,k;
?? ?for(i = 0; i < g.n; i++){
?? ??? ?lowcost[i] = g.edges[v][i];
?? ??? ?closet[i] = v;
?? ?}
?? ?for(i = 1; i < g.n; i++){
?? ??? ?min = M;
?? ??? ?for(j = 0; j < g.n; j++){
?? ??? ??? ?if(lowcost[j] != 0 && lowcost[j] < min){
?? ??? ??? ??? ?min = lowcost[j];
?? ??? ??? ??? ?k = j;
?? ??? ??? ?}
?? ??? ?}
?? ??? ?printf("邊(%d, %d)權(quán)為: %d", v, k, lowcost[k]);
?? ??? ?lowcost[k] = 0;
?? ??? ?
?? ??? ?for(j = 0; j < g.n; j++){
?? ??? ??? ?if(lowcost[j] != 0 && lowcost[j] > g.edges[k][j])
?? ??? ??? ?{
?? ??? ??? ??? ?lowcost[j] = g.edges[k][j];
?? ??? ??? ??? ?closet[j] = k;
?? ??? ??? ?}
?? ??? ?}
?? ?}
}


Kruskal?
總結(jié):對(duì)所有邊的權(quán)重值按照升序排列,依次選取權(quán)重較小的邊,
?? ? 確保不構(gòu)成回路(選中的邊的所有結(jié)點(diǎn)不能重復(fù)出現(xiàn)在新加入的一條邊中) ?? ?
?? ??
#define 32367
typedef struct{
?? ?int u;
?? ?int v;
?? ?int w;
?? ?//邊的始點(diǎn), 重點(diǎn), 權(quán)重?
}Edge;

void Kruskal(MatGraph h){
?? ?
?? ?int i, j, u1, v1, sn1, sn2, k;
?? ?int vset[MAXV];
?? ?Edge E[MaxSize];
?? ?
?? ?k = 0;//指示數(shù)組E的下標(biāo)
?? ?
?? ?//對(duì)于邊(權(quán)重)初始化?
?? ?for(i = 0; i < g.n; i++){
?? ??? ?for(j = i + 1; j < g.n; j++)//上三角?
?? ??? ??? ?if(g.edge[i][j] != M)//M = 32367
?? ??? ??? ?{
?? ??? ??? ??? ?E[k].u = i; E[k].v = j;
?? ??? ??? ??? ?E[k].w = g.edge[i][j]; k++;
?? ??? ??? ?}
?? ?}
?? ?//冒泡排序最簡(jiǎn)單?
?? ?Sort(E, edge); //升序, 權(quán)值遞增?
?? ?
?? ?for(i = 0; i < g.n; i++)//初始化輔助數(shù)組?
?? ??? ?vset[i] = i;
?? ??? ?
?? ?k = 1;//k:當(dāng)前構(gòu)造生成樹的第幾條邊, 初始值為1
?? ?j = 0;//E中邊的下標(biāo)
?? ?while(k < g.n){
?? ??? ?
?? ??? ?u1 = E[j].u;
?? ??? ?v1 = E[j].v;
?? ??? ?sn1 = vset[u1];
?? ??? ?sn2 = vset[u2];
?? ??? ?
?? ??? ?if(sn1 != sn2){
?? ??? ??? ?printf("(%d, %d): %d", u1, v1, E[j].w);
?? ??? ??? ?k++;
?? ??? ??? ?for(i = 0; i < g.n; i++){
?? ??? ??? ??? ?if(vset[i] == sn2)
?? ??? ??? ??? ??? ?vset[i] = sn1;//改結(jié)點(diǎn)相同, 表示這兩個(gè)結(jié)點(diǎn)已經(jīng)形
?? ??? ??? ??? ??? ?//通路, 避免成環(huán)?
?? ??? ??? ?}
?? ??? ??? ?j++;?
?? ??? ?}?
?? ?}?
}

拓?fù)渑判?/p>

原理: 對(duì)于鄰接矩陣
找入度為零的結(jié)點(diǎn)i, 即列為零的結(jié)點(diǎn),標(biāo)記, 將其刪除, 刪除鄰接邊即將序號(hào)i的行置零 , 重復(fù)...

鄰接表
加一個(gè)輔助數(shù)組記錄每個(gè)結(jié)點(diǎn)的入度; 入度為0, 入棧;?
棧非空, 出棧, 刪除鄰接邊;
即輔助數(shù)組鄰接點(diǎn)的總數(shù)count-1;?

//鄰接表定義如下
typedef struct ANode{
?? ?int adjvex; // 該邊的終點(diǎn)編號(hào)?
?? ?struct Anode *nextarc;
}ArcNode;?
typedef struct{
?? ?Vertex data;
?? ?int count;//輔助數(shù)組, 存放入度?
?? ?ArcNode *firstarc;
}VNode;
typedef struct{
?? ?VNode adjlist[MAV];
?? ?int n, e;
}AdjGraph;

拓?fù)渑判?br /> //基于鄰接表?
void TopSort(AdjGraph *G){
??? ?int i, j;
??? ?int st[MAXV], ?top = -1;//棧的指針
?? ?ArcNode *p;
?? ?
?? ?for(i = 0; i < G->n;i++){//入度置初值為0?
?? ??? ?G->adjlist[i].count = 0;
?? ?}?
?? ?for(i = 0; i < G->n; i++){//求所有頂點(diǎn)的入度?
?? ??? ?p = G->adjlist[i].firstarc;
?? ??? ?while(p!=NULL){
?? ??? ??? ?G->adjlist[p->adjvex].count++;
?? ??? ??? ?p = p->nextarc;//鄰接表?
?? ??? ?}
?? ?}
?? ?for(i = 0; i < G.n; i++){//入度為零進(jìn)棧?
?? ??? ?if(G->adjlist[i].count == 0){
?? ??? ??? ?top++;
?? ??? ??? ?st[top] = i;
?? ??? ?}
?? ?}
?? ?
?? ?while(top != -2){
?? ??? ?
?? ??? ?i = st[top]; top--;//出棧一個(gè)頂點(diǎn)i?
?? ??? ?printf("%d", i);
?? ??? ?
?? ??? ?p = G->adjlist[i].firstarc;
?? ??? ?while(p != NULL){
?? ??? ??? ?j = p->adjvex;//找出p的鄰接點(diǎn),入度-1?
?? ??? ??? ?G->adjlist[j].count--;
?? ??? ??? ?if(G->adjlist[j].count == 0){//入度為0入棧?
?? ??? ??? ??? ?top++;
?? ??? ??? ??? ?st[top] = j;
?? ??? ??? ?}
?? ??? ??? ?p = p->nextarc;
?? ??? ?}
?? ??? ?
?? ?}
?}
?
AOE網(wǎng)--邊表示活動(dòng)的網(wǎng)
唯一入度為0的頂點(diǎn)為源點(diǎn),唯一出度為0的頂點(diǎn)為匯點(diǎn)
源點(diǎn)到匯點(diǎn)的最長(zhǎng)路徑長(zhǎng)度為整個(gè)工程任務(wù)所需時(shí)間,稱為關(guān)鍵路徑
關(guān)鍵路徑上的活動(dòng)稱為關(guān)鍵活動(dòng).


//迪杰斯特算法 看PPT,難度較大?
void Dijkstra(MatGraph g, int v){ // v is the original dot.
?? ?int dist[MAXV], path[MAXV]; ? //dist is to memorize the weighted length of the path.
?? ?//path is used to memorize the node of the path
?? ?int s[MAXV]; //to mark the node whether have been used.
?? ?int mindist, i, j;
?? ?
?? ?for(i = 0; i < g.n; i++){
?? ??? ?dist[i] = g.edges[v][i]; //Firstly store the weighted length of the related edge.
?? ??? ?//If it is not relevant to it, put infinite on it. If it is itself, put 0 on it
?? ??? ?s[i] = 0;//s[] is cleared.
?? ??? ?if(g.edge[v][i] < INF)//如果v和i鄰接那么賦值i的鄰接點(diǎn)為v?
?? ??? ??? ?path[i] = v;
?? ??? ?else
?? ??? ??? ?path[i] = -1;//path is used to memorize the node before the latest
?? ??? ?//if it is -1, proven there is no path.
?? ?s[v] =1;?
?? ?for(i = 0; i < g.n; i++){//找出路徑長(zhǎng)度最小頂點(diǎn)u?
?? ??? ?mindis = INF;
?? ??? ?for(j = 0; j < g.n; j++)//Find out the shortest length of the node.
?? ??? ??? ?if(s[j] == 0 && dist[j] < mindis){
?? ??? ??? ??? ?u = j;
?? ??? ??? ??? ?mindis = dist[j];
?? ??? ??? ?}
?? ??? ?s[u] = 1;//node u is added into s//u has been used
?? ??? ?for(j = 0; j < g.n; j++)
?? ??? ??? ?if(s[j] == 0)//s[j]is not used
?? ??? ??? ??? ?if(g.edge[u][j]<INF && dist[u]+g.edge[u][j]<dist[j]){
?? ??? ??? ??? ??? ?dist[j] = dist[u]+g.edges[u][j];
?? ??? ??? ??? ??? ?path[j] = u;?
?? ??? ??? ??? ?}
?? ?}?? ?
?? ?}
?? ?Dispath(dist, path, s, g.n, v);//printf
} ?

對(duì)于多源點(diǎn)最短路徑問題
//佛洛里得算法 難度大,看ppt?
void Floyd(MatGraph g){
?? ?int A[MAXVEX][MAXVEX];//記錄路徑長(zhǎng)度
?? ?int path[MAXVEX][MAXVEX];//記錄路徑?
?? ?int i, j, k;
?? ?for(i = 0; i < g.n; i++)
?? ??? ?for(j = 0; j < g.n; j++){
?? ??? ??? ?A[i][j] = g.edges[i][j];
?? ??? ??? ?if(i!= j && g.edges[i][j] < INF)
?? ??? ??? ??? ?path[i][j] = i;
?? ??? ??? ?else
?? ??? ??? ??? ?path[i][j] = -1;//自環(huán)或者不存在鄰接邊?
?? ??? ?}?
?? ?for(k = 0; k < g.n; k++){//O(n^3)
?? ??? ?for(i = 0; i < g.n; i++)
?? ??? ??? ?for(j = 0; j < g.n; j++)
?? ??? ??? ??? ?if(A[i][j] > A[i][k]+A[k][i]){
?? ??? ??? ??? ?//i, j 之間有兩種形式, i直接到j(luò);
?? ??? ??? ??? ?//或者i經(jīng)過k到達(dá)j?
?? ??? ??? ??? ??? ?A[i][j] = A[i][k]+A[k][i];
?? ??? ??? ??? ??? ?path[i][j] = path[k][j];
?? ??? ??? ??? ??? ?//修改最短路徑經(jīng)過k?
?? ??? ??? ??? ?}
?? ?}
}?

第七章總結(jié):圖是最復(fù)雜的線性表.分類很多根據(jù)弧的有向與否,連通性,邊數(shù)量,權(quán)....
儲(chǔ)存分為邊集合(鄰接矩陣), 鏈接的方式(鄰接表,十字鏈表,鄰接多重表)
圖的遍歷分為深度遍歷和廣度優(yōu)先遍歷,前者遞歸,后者隊(duì)列!!!

應(yīng)用!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1?

第八章 查找

概念:列表(python,就相當(dāng)于數(shù)組),主關(guān)鍵詞,次關(guān)鍵字
查找:分為動(dòng)態(tài)和靜態(tài)查找 前者僅僅是查找, 后者插入找不到的元素或者刪除已經(jīng)查到的元素

?
基于線性表的查找

// 1.順序查找法
//思想:所給的關(guān)鍵字和表中元素的關(guān)鍵字逐個(gè)比較
定義如下:
#define SIZE 20
typedef struct{
?? ?int key;
?? ?int other_data;
}RecordType;?

typedef struct{
?? ?RecordType r[SIZE];//r[0]為工作單元?
?? ?int length;
}RecordList;

分為:設(shè)置監(jiān)視哨和不設(shè)監(jiān)視哨
監(jiān)視哨:r[0]防止越界

int SeqSearch(RecordList ?l, ?KeyType ?k)
//在順序表l中順序查找其關(guān)鍵字等于k的元素,若找到,則函數(shù)值為該元素在表中的位置,否則為0
{
?? ?int i;
?? ?l.r[0].key=k;?
?? ?i=l.length;
?? ?while (l.r[i].key!=k) ?i--;
?? ?return(i);
}

int SeqSearch(RecordList l, ?KeyType k)
//不用"監(jiān)視哨"法,在順序表中查找關(guān)鍵字等于k的元素
{
?? ?int i;
?? ?i=l.length;
?? ?while (i>=1&&l.r[i].key!=k) ?i--;
?? ?if (i>=1)?
?? ??? ?return(i);
?? ?else
?? ??? ?return (0);
}

//2.折半查找法
要求:順序儲(chǔ)存結(jié)構(gòu)(不能鏈表!!!),按照關(guān)鍵字大小有序排列(正序和逆序)
思想:利用mid=(high+low)/2(整數(shù)). 判斷條件:low<=high;

int BinSrch(RecordList ?l, ?KeyType ?k)
/*在有序表l中折半查找其關(guān)鍵字等于k的元素,若找到,則函數(shù)值為該元素在表中的
位置*/
{
?? ?int low,high,mid;
?? ?low=1; ?
?? ?high=l.length;/*置區(qū)間初值*/
?? ?while( low <= high)
?? ?{
?? ??? ?mid=(low+high) / 2;
?? ??? ?if ?(k==l.r[mid]. key) ?
?? ??? ??? ?return (mid);/*找到待查元素*/
?? ??? ?else ?
?? ??? ??? ?if (k<l.r[mid]. key)?
?? ??? ??? ??? ?high=mid-1;/*未找到,則繼續(xù)在前半?yún)^(qū)間進(jìn)行查找*/
?? ??? ??? ?else ?
?? ??? ??? ??? ?low=mid+1;/*繼續(xù)在后半?yún)^(qū)間進(jìn)行查找*/
?? ?}
?? ?return (0);
}

//3.分塊查找法
要求:列表分為子表,最后一個(gè)子表長(zhǎng)度可以不滿;索引表每個(gè)索引對(duì)應(yīng)每個(gè)塊(子表)的起始位置,記錄每個(gè)塊的最大(最小)
的關(guān)鍵字;索引表按照關(guān)鍵字有序排列


基于樹的查找法

二叉排序樹定義:元素大小關(guān)系:左子樹<根<右子樹,遞歸定義

結(jié)構(gòu)定義:
typedef struct node{
?? ?int key;
?? ?struct node *lchild, *rchild;
}BSTNode, *BSTree;
?
插入:?
遞歸算法?
void InsertBST(BSTree *bst, KeyType key)
/*若在二叉排序樹中不存在關(guān)鍵字等于key的元素,插入該元素*/
{?
?? ?BSTree s;
?? ?if (*bst == NULL)/*遞歸結(jié)束條件*/
?? ?{
?? ??? ?s=(BSTree)malloc(sizeof(BSTNode));/*申請(qǐng)新的結(jié)點(diǎn)s*/
?? ??? ?s-> key=key;
?? ??? ?s->lchild=NULL;?
?? ??? ?s->rchild=NULL;
?? ??? ?*bst=s;
?? ?}
?? ?else?
?? ??? ?if (key < (*bst)->key)
?? ??? ??? ?InsertBST(&((*bst)->lchild), key);/*將s插入左子樹*/
?? ??? ?else?
?? ??? ??? ?if (key > (*bst)->key)
?? ??? ??? ??? ?InsertBST(&((*bst)->rchild), key); /*將s插入右子樹*/
}

非遞歸: !!!!!!!!!!!!!!!
int ?InsertBST(BSTree ?*bst, ?KeyType ?K)
/*若在二叉排序樹中不存在關(guān)鍵字等于key的元素,插入該元素*/
{
?? ?BSTree ?f, q, s;
?? ?s=(BSTree)malloc(sizeof(BSTNode));
?? ?s->key = K;
?? ?s->lchild = NULL;
?? ?s->rchild = NULL;
?? ?
?? ?//空樹直接賦值?
?? ?if ( *bst == NULL )?
?? ?{?
?? ??? ?*bst = s;?
?? ??? ?return ?1;?
?? ?}
?? ?//指針跟蹤技術(shù)?
?? ?f = NULL;
?? ?q = *bst;
?? ?while( q )
?? ?{?
?? ??? ?if ( q->key == K )?
?? ??? ??? ?return ?0;
?? ??? ?if( K < q->key ) //小于走左邊?
?? ??? ?{?
?? ??? ??? ?f = q;?
?? ??? ??? ?q = q->lchild;?
?? ??? ?}
?? ??? ?else?
?? ??? ?{ ?
?? ??? ??? ?f = q;?
?? ??? ??? ?q = q->rchild;?
?? ??? ?}
?? ?}//走到頭仍然沒找到就插入?
?? ?if ( K < f->key )?
?? ??? ?f->lchild = s;?
?? ?else ?
?? ??? ?f->rchild = s;
?? ?return ?1; ?
}

創(chuàng)建二叉排序樹:
void ?CreateBST(BSTree ?*bst)
/*從鍵盤輸入元素的值,創(chuàng)建相應(yīng)的二叉排序樹*/
{?
?? ?KeyType key;
?? ?*bst=NULL;
?? ?scanf("%d", &key);
?? ?while (key!=ENDKEY) ? /*ENDKEY為自定義常量*/
?? ?{
?? ??? ?InsertBST(bst, key);
?? ??? ?scanf("%d", &key);
?? ?}
}?

查找:?
遞歸算法?
BSTree ?SearchBST(BSTree bst, KeyType key)
//在根指針bst所指二叉排序樹中,遞歸查找某關(guān)鍵字等于key的元素,若查找成功,返回指向該元素結(jié)點(diǎn)指針,否則返回空指針
{?
?? ?if (!bst)?
?? ??? ?return NULL;
?? ?else if (bst->key == key)
?? ??? ?return bst;//查找成功
?? ?else if (bst->key > key)
?? ??? ?return SearchBST(bst->lchild, key);//在左子樹繼續(xù)查找
?? ?else?
?? ??? ?return SearchBST(bst->rchild, key);//在右子樹繼續(xù)查找
}

二叉排序樹的刪除略顯復(fù)雜:
1.不存在,不動(dòng)
2.存在
2.1.葉子節(jié)點(diǎn):直接刪,free掉
2.2只有左右子樹一支:孩子改到刪去位置(孩子變?yōu)殡p親),free
2.3.左右孩子都有:
2.3.1處理1:
?? ?利用中序遍歷算法找到將要?jiǎng)h除結(jié)點(diǎn)p的直接前驅(qū)s,p左子樹變?yōu)槠潆p親的左孩子,右子樹變?yōu)槠淝膀?qū)s的右孩子?
2.3.2處理2:?
?? ?直接刪除結(jié)點(diǎn)p,p的前驅(qū)s代替p,free(s),s的左孩子為s的雙親的右孩子,p的右孩子為s的右孩子
!!!
BSTNode ?* DelBST(BSTree t, KeyType ?k) /*在二叉排序樹t中刪去關(guān)鍵字為k的結(jié)點(diǎn)*/
{
?? ?BSTNode ?*p, *f,*s ,*q;
?? ?p=t;?
?? ?f=NULL;
?? ?while(p) ?/*查找關(guān)鍵字為k的待刪結(jié)點(diǎn)p*/
?? ?{?
?? ??? ?if(p->key==k ) ?break; ?/*找到則跳出循環(huán)*/
?? ??? ?f=p; ? /*f指向p結(jié)點(diǎn)的雙親結(jié)點(diǎn)*/
?? ??? ?if(p->key>k) ?
?? ??? ??? ?p=p->lchild;
?? ??? ?else?
?? ??? ??? ?p=p->rchild;
?? ?}?
?? ?if(p==NULL) ?return t; ?/*若找不到,返回原來(lái)的二叉排序樹*/
?? ?if(p->lchild==NULL) ?/*p無(wú)左子樹*/
?? ?{?
?? ??? ?if(f==NULL)?
?? ??? ??? ?t=p->rchild; ?/*p是原二叉排序樹的根*/
?? ??? ?else?
?? ??? ??? ?if(f->lchild==p) ?/*p是f的左孩子*/
?? ??? ??? ??? ?f->lchild=p->rchild ; ?/*將p的右子樹鏈到f的左鏈上*/
?? ??? ??? ?else ?/*p是f的右孩子*/
?? ??? ??? ??? ?f->rchild=p->rchild ; ?/*將p的右子樹鏈到f的右鏈上*/
?? ??? ??? ?free(p); ?/*釋放被刪除的結(jié)點(diǎn)p*/
?? ?}
?? ?else ?/*p有左子樹*/
?? ?{?
?? ??? ?q=p;?
?? ??? ?s=p->lchild;
?? ??? ?while(s->rchild) ?/*在p的左子樹中查找最右下結(jié)點(diǎn)*/
?? ??? ?{
?? ??? ??? ?q=s;?
?? ??? ??? ?s=s->rchild;
?? ??? ?}
?? ??? ?if(q==p)?
?? ??? ??? ?q->lchild=s->lchild ; ?/*將s的左子樹鏈到q上*/
?? ??? ?else?
?? ??? ??? ?q->rchild=s->lchild;
?? ??? ?p->key=s->key; ?/*將s的值賦給p*/
?? ??? ?free(s);
?? ?}
?? ?return t;
} ?
?? ?
平衡二叉排序樹:左子樹右子樹高度絕對(duì)值之差小于等于1
插入算法:LL,RR,LR,RL型

結(jié)構(gòu)定義中含平衡因子代碼如下:
?? ?
void ?ins_AVLtree(AVLTree ?*avlt , ?KeyType ?K)
/*在平衡二叉樹中插入元素k,使之成為一棵新的平衡二叉排序樹*/
{
?? ?AVLTNode *S;
?? ?AVLTNode *A,*FA,*p,*fp,*B,*C;
?? ?S=(AVLTree)malloc(sizeof(AVLTNode));
?? ?S->key=K;?
?? ?S->lchild=S->rchild=NULL;
?? ?S->bf=0;
?? ?if (*avlt==NULL) ?
?? ??? ?*avlt=S;
?? ?else?
?? ?{?
?? ?/* 首先查找S的插入位置fp,同時(shí)記錄距S的插入位置最近且
?? ??? ?平衡因子不等于0(等于-1或1)的結(jié)點(diǎn)A,A為可能的失衡結(jié)點(diǎn)*/
?? ??? ?A=*avlt; ?FA=NULL;
?? ??? ?p=*avlt; ?fp=NULL;
?? ??? ?while ?(p!=NULL)
?? ??? ?{?
?? ??? ??? ?if (p->bf!=0)?
?? ??? ??? ?{
?? ??? ??? ??? ?A=p; FA =fp;
?? ??? ??? ?}
?? ??? ??? ?fp=p;
?? ??? ??? ?if ?(K < p->key) ?
?? ??? ??? ??? ?p=p->lchild;
?? ??? ??? ?else ?
?? ??? ??? ??? ?p=p->rchild;
?? ??? ?}
?? ??? ?/* 插入S*/
?? ??? ?if (K < fp->key)?
?? ??? ??? ?fp->lchild=S;
?? ??? ?else
?? ??? ??? ?fp->rchild=S;
?? ??? ?/* 確定結(jié)點(diǎn)B,并修改A的平衡因子 */
?? ??? ?if (K < A->key)
?? ??? ?{
?? ??? ??? ?B=A->lchild;
?? ??? ??? ?A->bf=A->bf+1;
?? ??? ?}
?? ??? ?else
?? ??? ?{
?? ??? ??? ?B=A->rchild;
?? ??? ??? ?A->bf=A->bf-1;
?? ??? ?}
?? ??? ?/* 修改B到S路徑上各結(jié)點(diǎn)的平衡因子(原值均為0)*/
?? ??? ?p=B;
?? ??? ?while (p!=S)
?? ??? ?{
?? ??? ??? ?if ?(K < p->key)
?? ??? ??? ?{
?? ??? ??? ??? ?p->bf=1;
?? ??? ??? ??? ?p=p->lchild;
?? ??? ??? ?}
?? ??? ??? ?else
?? ??? ??? ?{
?? ??? ??? ??? ?p->bf=-1;
?? ??? ??? ??? ?p=p->rchild;
?? ??? ??? ?}
?? ??? ??? ?/* 判斷失衡類型并做相應(yīng)處理 */
?? ??? ??? ?if ?(A->bf==2 && B->bf==1) ? ? ? /* LL型 */
?? ??? ??? ?{
?? ??? ??? ??? ?B=A->lchild;
?? ??? ??? ??? ?A->lchild=B->rchild;
?? ??? ??? ??? ?B->rchild=A;
?? ??? ??? ??? ?A->bf=0;
?? ??? ??? ??? ?B->bf=0;
?? ??? ??? ??? ?if (FA==NULL)?
?? ??? ??? ??? ??? ?*avlt=B;
?? ??? ??? ??? ?else?
?? ??? ??? ??? ??? ?if (A==FA->lchild)?
?? ??? ??? ??? ??? ??? ?FA->lchild=B;
?? ??? ??? ??? ??? ?else?
?? ??? ??? ??? ??? ??? ?FA->rchild=B;
?? ??? ??? ?}
?? ??? ??? ?else
?? ??? ??? ??? ?if (A->bf==2 && B->bf==-1) ? ? ? /* LR型 */
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?B=A->lchild;
?? ??? ??? ??? ??? ?C=B->rchild;
?? ??? ??? ??? ??? ?B->rchild=C->lchild;
?? ??? ??? ??? ??? ?A->lchild=C->rchild;
?? ??? ??? ??? ??? ?C->lchild=B;
?? ??? ??? ??? ??? ?C->rchild=A;
?? ??? ??? ??? ??? ?if (S->key < C->key)
?? ??? ??? ??? ??? ?{?
?? ??? ??? ??? ??? ??? ?A->bf=-1;
?? ??? ??? ??? ??? ??? ?B->bf=0;
?? ??? ??? ??? ??? ??? ?C->bf=0;
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ?else?
?? ??? ??? ??? ??? ??? ?if (S->key >C->key)
?? ??? ??? ??? ??? ??? ?{
?? ??? ??? ??? ??? ??? ??? ?A->bf=0;
?? ??? ??? ??? ??? ??? ??? ?B->bf=1;
?? ??? ??? ??? ??? ??? ??? ?C->bf=0;
?? ??? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ??? ?else
?? ??? ??? ??? ??? ??? ?{?
?? ??? ??? ??? ??? ??? ??? ?A->bf=0;
?? ??? ??? ??? ??? ??? ??? ?B->bf=0;
?? ??? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ??? ?if ?(FA==NULL)?
?? ??? ??? ??? ??? ??? ??? ?*avlt=C;
?? ??? ??? ??? ??? ??? ?else?
?? ??? ??? ??? ??? ??? ??? ?if (A==FA->lchild)?
?? ??? ??? ??? ??? ??? ??? ??? ?FA->lchild=C;
?? ??? ??? ??? ??? ??? ??? ?else?
?? ??? ??? ??? ??? ??? ??? ??? ?FA->rchild=C;
?? ??? ??? ??? ?}
?? ??? ??? ??? ?else?
?? ??? ??? ??? ??? ?if ?(A->bf==-2 && B->bf==1) ? ? ? /* RL型 */
?? ??? ??? ??? ??? ?{
?? ??? ??? ??? ??? ??? ?B=A->rchild;
?? ??? ??? ??? ??? ??? ?C=B->lchild;
?? ??? ??? ??? ??? ??? ?B->lchild=C->rchild;
?? ??? ??? ??? ??? ??? ?A->rchild=C->lchild;
?? ??? ??? ??? ??? ??? ?C->lchild=A;
?? ??? ??? ??? ??? ??? ?C->rchild=B;
?? ??? ??? ??? ??? ??? ?if (S->key <C->key)?
?? ??? ??? ??? ??? ??? ?{?
?? ??? ??? ??? ??? ??? ??? ?A->bf=0;
?? ??? ??? ??? ??? ??? ??? ?B->bf=-1;
?? ??? ??? ??? ??? ??? ??? ?C->bf=0;
?? ??? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ??? ?else?
?? ??? ??? ??? ??? ??? ??? ?if (S->key >C->key)
?? ??? ??? ??? ??? ??? ??? ?{
?? ??? ??? ??? ??? ??? ??? ??? ?A->bf=1;
?? ??? ??? ??? ??? ??? ??? ??? ?B->bf=0;
?? ??? ??? ??? ??? ??? ??? ??? ?C->bf=0;
?? ??? ??? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ??? ??? ?else?
?? ??? ??? ??? ??? ??? ??? ?{?
?? ??? ??? ??? ??? ??? ??? ??? ?A->bf=0;
?? ??? ??? ??? ??? ??? ??? ??? ?B->bf=0;
?? ??? ??? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ??? ??? ?if (FA==NULL) ?
?? ??? ??? ??? ??? ??? ??? ??? ?*avlt=C;
?? ??? ??? ??? ??? ??? ??? ?else
?? ??? ??? ??? ??? ??? ??? ??? ?if (A==FA->lchild)?
?? ??? ??? ??? ??? ??? ??? ??? ??? ?FA->lchild=C;
?? ??? ??? ??? ??? ??? ??? ??? ?else ?
?? ??? ??? ??? ??? ??? ??? ??? ??? ?FA->rchild=C;
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ?else?
?? ??? ??? ??? ??? ??? ?if (A->bf==-2 && B->bf==-1) ? ? ? /* RR型 */
?? ??? ??? ??? ??? ??? ?{
?? ??? ??? ??? ??? ??? ??? ?B=A->rchild;
?? ??? ??? ??? ??? ??? ??? ?A->rchild=B->lchild;
?? ??? ??? ??? ??? ??? ??? ?B->lchild=A;
?? ??? ??? ??? ??? ??? ??? ?A->bf=0;
?? ??? ??? ??? ??? ??? ??? ?B->bf=0;
?? ??? ??? ??? ??? ??? ??? ?if (FA==NULL)?
?? ??? ??? ??? ??? ??? ??? ??? ?*avlt=B;
?? ??? ??? ??? ??? ??? ??? ?else
?? ??? ??? ??? ??? ??? ??? ??? ?if (A==FA->lchild)
?? ??? ??? ??? ??? ??? ??? ??? ??? ?FA->lchild=B;
?? ??? ??? ??? ??? ??? ??? ??? ?else?
?? ??? ??? ??? ??? ??? ??? ??? ??? ?FA->rchild=B;
?? ??? ??? ??? ??? ??? ?}
?? ??? ??? ??? ?}
?? ??? ?}
}?

icoding例題:
?? ?
AVL添加
平衡二叉樹,是一種二叉排序樹,其中每個(gè)結(jié)點(diǎn)的左子樹和右子樹的高度差至多等于1。
它是一種高度平衡的二叉排序樹。現(xiàn)二叉平衡樹結(jié)點(diǎn)定義如下:

typedef struct node
{
? ? int val;
? ? struct node *left;
? ? struct node *right;
? ? struct node *parent;
? ? int height;
} node_t;
//請(qǐng)實(shí)現(xiàn)平衡二叉樹的插入算法:

//向根為 root 的平衡二叉樹插入新元素 val,成功后返回新平衡二叉樹根結(jié)點(diǎn)
node_t *avl_insert(node_t *root, int val);

#include <stdlib.h>
#include <stdio.h>
#include "avl.h"

int get_height(node_t *p){
?? ?if(!p)
?? ??? ?return 0;
?? ?else
?? ??? ?return p->height;
}

node_t* avl_insert(node_t *root, int val){
//首先清晰字母定義;
//val新插入結(jié)點(diǎn)元素值,height高度!!!?
//定義查找過程中出現(xiàn)的距離插入結(jié)點(diǎn)最近的平衡因子不為零的結(jié)點(diǎn)A
//定義A的孩子結(jié)點(diǎn)為B,需要旋轉(zhuǎn)的結(jié)點(diǎn)
//定義插入節(jié)點(diǎn)為s,s的值為val
//平衡因子:左子樹減去右子樹深度?

?? ?node_t *s, *A, *B, *C, *p, *fp;
?? ?//依次:插入點(diǎn), 失衡點(diǎn)(也可能是旋轉(zhuǎn)點(diǎn)),旋轉(zhuǎn)點(diǎn),旋轉(zhuǎn)點(diǎn)(也可能是插入點(diǎn)=s),動(dòng)點(diǎn),跟蹤點(diǎn)
?? ?int i, k;//平衡因子?
?? ?
?? ?s = (node_t *)malloc(sizeof(node_t));
?? ?if(!s) return NULL;
?? ?
?? ?s->val = val;
?? ?s->left = s->parent = s->right = NULL;
?? ?s->height = 1;
?? ?
?? ?//類似于指針跟蹤技術(shù),p為動(dòng)指針,A為跟蹤指針?
?? ?A = root; A->parent = NULL;
?? ?p = root; p->parent = NULL;
?? ?
?? ?//找出A?
?? ?if(!p)
?? ??? ?root = s;
?? ?else{
?? ??? ?while(p){
?? ??? ??? ?//先找出最近的A->height!=0的結(jié)點(diǎn), 就是最后的失衡點(diǎn)
?? ??? ??? ?i = get_height(p->left) - get_height(p->right);?
?? ??? ??? ?if(i){
?? ??? ??? ??? ?A = p;
?? ??? ??? ??? ?A->parent = p->parent;
?? ??? ??? ?}
?? ??? ??? ?//fp跟蹤p,因?yàn)橄乱徊絧會(huì)往下移動(dòng),p最終指向s的那一層?
?? ??? ??? ?fp = p;
?? ??? ??? ?if(val < p->val)
?? ??? ??? ??? ?p = p->left;
?? ??? ??? ?else
?? ??? ??? ??? ?p = p->right;
?? ??? ??? ?}//p最終指向NULL就推出循環(huán)?? ??
?? ?}?
?? ?
?? ?//插入, 此時(shí)fp是p的前一個(gè)結(jié)點(diǎn),p指向空?
?? ?if(val < fp->val)
?? ??? ?fp->left = s;
?? ?else
?? ??? ?fp->right = s;
?? ??? ?
?? ?//確定旋轉(zhuǎn)結(jié)點(diǎn)B,修改A的平衡因子
?? ?if(val < A->val)
?? ??? ?B = A->left;
?? ?else
?? ??? ?B = A->right;

?? ?A->height++;
?? ?
?? ?//修改路徑B到s的高度, B在A的下一層?
?? ?p = B; // p最終指向s, 之前指向的是s這一層,但是是空

?? ?while(p != s){
?? ??? ?p->height++;
?? ??? ?if(val < p->val)
?? ??? ??? ?p = p->left;?
?? ??? ?else
?? ??? ??? ?p = p->right;?? ?
?? ?}
?? ?//最終s的高度沒有++的?
?? ??? ?
?? ?
?? ?//調(diào)整完高度就修改結(jié)點(diǎn)和指針, 首先需要判斷失衡類型
?? ?//分為L(zhǎng)L,LR,RR,RL
?? ?//結(jié)點(diǎn)A,B平衡因子在修改指針的過程中會(huì)變化,但是路徑上的結(jié)點(diǎn)不會(huì)
?? ?//指針修改包括s結(jié)點(diǎn)指針和原來(lái)雙親結(jié)點(diǎn)指針?
?? ?i = get_height(A->left) - get_height(A->right);
?? ?k = get_height(B->left) - get_height(B->right);?
?? ?
?? ?if(i == 2 && k == 1){//LL
?? ??? ?//B作為旋轉(zhuǎn)結(jié)點(diǎn)
?? ??? ?//先改結(jié)點(diǎn)指針, 此時(shí)s插入在B的左子樹下, 原來(lái)可以認(rèn)為B左右子樹,A右子樹均為空
?? ??? ?A->left = B->right;
?? ??? ?B->right = A;
?? ??? ?
?? ??? ?//考慮原來(lái)A結(jié)點(diǎn)的指針,改成B后相應(yīng)的指針也要改變,下面同理
?? ??? ?if(A->parent == NULL)
?? ??? ??? ?root = B;
?? ??? ?else if(A->parent->left == A)
?? ??? ??? ?A->parent->left = B;
?? ??? ?else
?? ??? ??? ?A->parent->right = B;?? ??? ?
?? ?}
?? ?else if(i == -2 && k == -1){//RR
?? ??? ?A->right = B->left;
?? ??? ?B->left = A;
?? ??? ?
?? ??? ?if(A->parent == NULL)
?? ??? ??? ?root = B;
?? ??? ?else if(A->parent->left == A)
?? ??? ??? ?A->parent->left = B;
?? ??? ?else
?? ??? ??? ?A->parent->right = B;?? ?
?? ?}
?? ?else if(i == 2 && k == -1){//LR
?? ??? ?//此時(shí)認(rèn)為C的左右子樹空,B逆時(shí)針旋轉(zhuǎn),A順時(shí)針旋轉(zhuǎn), s插入C的左子樹或者右子樹?
?? ??? ?//如果C結(jié)點(diǎn)也是空,也就是說(shuō)B右子樹空,那么直接插入C=s為B右子樹,此時(shí)A右子樹也是空的?
?? ??? ?C = B->right;
?? ??? ?B->right = C->left;
?? ??? ?A->left = C->right;
?? ??? ?C->left = B;
?? ??? ?C->right = A;
?? ??? ?
?? ??? ?if(A->parent == NULL)
?? ??? ??? ?root = C;
?? ??? ?else if(A->parent->left == A)
?? ??? ??? ?A->parent->left = C;
?? ??? ?else
?? ??? ??? ?A->parent->right = C;
?? ?}
?? ?else if(i == -2 && k == 1){//RL?
?? ??? ?//和LR一樣,畫圖來(lái)看就好
?? ??? ?C = B->left;
?? ??? ?A->right = C->left;
?? ??? ?B->left = C->right;
?? ??? ?C->left = A;
?? ??? ?C->right = B;
?? ??? ?
?? ??? ?if(A->parent == NULL)
?? ??? ??? ?root = C;
?? ??? ?else if(A->parent->left == A)
?? ??? ??? ?A->parent->left = C;
?? ??? ?else
?? ??? ??? ?A->parent->right = C;
?? ?}
?? ?return root;
}?


計(jì)算式查找法:hash(python的字典就是這么存的)

//hash:
1.數(shù)字分析法:選擇合適位數(shù)的分布均勻的關(guān)鍵字?
2.平方取中法:求關(guān)鍵字平方值,取中間,重復(fù)概率低?
3.分段疊加法:折疊法,移位法
4.除留余數(shù)法:取余除數(shù)為小于等于表長(zhǎng)的最大素?cái)?shù)?
5.偽隨機(jī)數(shù)法:電腦生成偽隨機(jī)數(shù)?
?? ?
處理沖突!!!!:
1.開放地址法(再散列法):
1.1.線性探測(cè)再散列:di = 1,2,3......
1.2.二次探測(cè)再散列:di = 1^2, -1^2, 2^2, -2^2,......?
1.3.偽隨機(jī)探測(cè)再散列: ...

2.再哈希法
3.鏈地址法:!!!
4.建立公共溢出區(qū):分為基本表和溢出表

icoding:
?? ?
哈希表創(chuàng)建
typedef enum{
? ? HASH_OK,
? ? HASH_ERROR,
? ? HASH_ADDED,
? ? HASH_REPLACED_VALUE,
? ? HASH_ALREADY_ADDED,
? ? HASH_DELETED,
? ? HASH_NOT_FOUND,
} HASH_RESULT;
typedef struct __HashEntry HashEntry;
struct __HashEntry{
? ? union{
? ? ? ? char ?*str_value;
? ? ? ? double dbl_value;
? ? ? ? int ? ? ? int_value;
? ? } key;
? ? union{
? ? ? ? char ?*str_value;
? ? ? ? double dbl_value;
? ? ? ? int ? ? ? int_value;
? ? ? ? long ? long_value;
? ? ? ? void ?*ptr_value;
? ? } value;
? ? HashEntry *next;
};
struct __HashTable{
? ? HashEntry **bucket; ? ? ? ?
? ? int size;
? ? HASH_RESULT last_error;
};
typedef struct __HashTable HashTable;
// 創(chuàng)建大小為hash_size的哈希表,創(chuàng)建成功后返回HashTable類型的指針,否則返回NULL。
HashTable *create_hash(int hash_size);
哈希表相關(guān)說(shuō)明:

HASH_RESULT 類型為相關(guān)函數(shù)的返回類型
HashEntry 為哈希表所保存元素(即鍵值對(duì) 《key, value》)類型
HashTable 為哈希表,其中 bucket 指向大小為size的、元素類型為 HashEntry*的指針數(shù)組
哈希表采用鏈地址法處理沖突
請(qǐng)實(shí)現(xiàn) create_hash 函數(shù),創(chuàng)建指定大小的哈希表。
#include <stdio.h>
#include <stdlib.h>
#include "hash.h"

HashTable* create_hash(int size){
?? ?HashTable *r;
?? ?
?? ?r = (HashTable *)malloc(sizeof(HashTable));
?? ?if(r == NULL) return NULL;
?? ?
?? ?r->bucket = (HashEntry **)malloc(size * sizeof(HashEntry *));
?? ?if(r->bucket == NULL){
?? ??? ?free(r);
?? ??? ?return NULL;
?? ?}
?? ?
?? ?r->size = size;
?? ?r->last_error = HASH_OK;
?? ?return r;
}

添加:?
向哈希表中添加元素,其中鍵類型為char*, 元素類型為int。
HASH_RESULT hash_add_int(HashTable * table, const char * key, int value);

哈希表相關(guān)說(shuō)明:
HASH_RESULT 類型為相關(guān)函數(shù)的返回類型
HashEntry 為哈希表所保存元素(即鍵值對(duì) 《key, value》)類型
HashTable 為哈希表,其中 bucket 指向大小為size的、元素類型為 HashEntry*的指針數(shù)組
哈希表采用鏈地址法處理沖突
請(qǐng)實(shí)現(xiàn) hash_add_int 函數(shù),向哈希表中添加元素,其中鍵類型為char*, 元素類型為int。
在添加過程中,如果要添加的鍵值key已在哈希表中,且對(duì)應(yīng)的值value也已存在,則函數(shù)返回 HASH_ALREADY_ADDED;
如果要添加的鍵值key已在哈希表中,但對(duì)應(yīng)的值value不同,函數(shù)將value值更新到哈希表中,之后返回 HASH_REPLACED_VALUE
如果要添加的鍵值key不在哈希表中,則函數(shù)創(chuàng)建 HashEntry 類型,并將其加入到哈希表中,且函數(shù)返回 HASH_ADDED。
本題所用的哈希函數(shù)如下:
long hash_string(const char *str)
{
? ? long hash = 5381;
? ? int c;

? ? while (c = *str++)
? ? ? ? hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
? ? if(hash < 0)
? ? ? ? hash *= -1;
? ? return hash;
}

#include <stdio.h> ? ?
#include "stdlib.h"
#include "hash.h" ? ? ?
#include <string.h>
?
HASH_RESULT hash_add_int(HashTable *table, const char *key, int value ){
?? ?
?? ?HashEntry *p;//指的是每一個(gè)鍵值對(duì)?
?? ?int h = hash_string(key) % table->size;//保存哈希函數(shù)返回值?
?? ?//int類型也可以?
?? ?// !h %= table->size; 編譯器奇怪的不通過.....?
?? ?
?? ?//該關(guān)鍵字對(duì)應(yīng)的哈希表中鍵值對(duì)不存在, 分配節(jié)點(diǎn)存入?
?? ?if(!table->bucket[h]){
?? ??? ?p = (HashEntry *)malloc(sizeof(HashEntry));
?? ??? ?if(!p) return HASH_ERROR;
?? ??? ?p->key.str_value = (char *)malloc(strlen(key));
?? ??? ?if(!p->key.str_value){
?? ??? ??? ?free(p);
?? ??? ??? ?return HASH_ERROR;
?? ??? ?}
?? ??? ?//!!!!字符串拷貝?
?? ??? ?strcpy(p->key.str_value, key);
?? ??? ?p->value.int_value = value;
?? ??? ?//最好還是置空?
?? ??? ?p->next = NULL;
?? ??? ?table->bucket[h] = p;
?? ??? ?
?? ??? ?return HASH_ADDED;
?? ?}

?? ?//關(guān)鍵字對(duì)應(yīng)的哈希表中該位置存在鍵值對(duì),判斷重復(fù)或者沖突?
?? ?p = table->bucket[h];
?? ?while(p){?? ?
?
?? ??? ?//關(guān)鍵字相同?
?? ??? ?if(strcmp(key, p->key.str_value)==0){
?? ??? ??? ?//判斷值?
?? ??? ??? ?if(p->value.int_value == value){
?? ??? ??? ??? ?return HASH_ALREADY_ADDED;
?? ??? ??? ?}
?? ??? ??? ?else{
?? ??? ??? ??? ?p->value.int_value = value;
?? ??? ??? ??? ?return HASH_REPLACED_VALUE;
?? ??? ??? ?}
?? ??? ?}
?? ??? ?//鏈地址法?
?? ??? ?else{
?? ??? ??? ?if(p->next)
?? ??? ??? ??? ?p = p->next;
?? ??? ??? ?else
?? ??? ??? ??? ?break;
?? ??? ?}
?? ?
?? ?}
?? ?//循環(huán)完成后?
?? ?//p指向最后一個(gè)結(jié)點(diǎn)?
?? ?HashEntry *q;//q接到p后面?
?? ?q = (HashEntry *)malloc(sizeof(HashEntry));
?? ?if(!q) return HASH_ERROR;
?? ?
?? ?q->key.str_value = (char *)malloc(strlen(key));
?? ?if(!q->key.str_value){
?? ??? ?free(q);
?? ??? ?return HASH_ERROR;
?? ?}
?? ?
?? ?strcpy(q->key.str_value, key);
?? ?q->value.int_value = value;
?? ?q->next = NULL;
?? ?p->next = q;
?? ?
?? ?return HASH_ADDED;
?? ??? ?
}
?
第八章總結(jié):?
查找機(jī)制: 基于線性結(jié)構(gòu):靜態(tài)查找表,基于比較的順序檢索和折半檢索(有點(diǎn)像快排)
?? ??? ? ?基于樹形結(jié)構(gòu):動(dòng)態(tài)查找?
?? ??? ? ?哈希計(jì)算式查找: 根據(jù)關(guān)鍵字計(jì)算存儲(chǔ)地址
二叉排序樹:值域左子樹 < 根 < 右子樹
其構(gòu)建:每次從根節(jié)點(diǎn)開始比較,順次比較插入
對(duì)于二叉排序樹中序遍歷得到遞增序列
查找:比較次數(shù)不超過樹的深度,平均查找長(zhǎng)度O(log2(n)).?
平衡二叉樹...(AVL)?
Hash法...?

第九章 內(nèi)部排序?

排序:重點(diǎn)在于對(duì)于記錄的關(guān)鍵字進(jìn)行排序,得到按關(guān)鍵字有序記錄序列
分為:
?? ?A.內(nèi)部排序: 排序過程在內(nèi)存中進(jìn)行?
?? ?B.外部排序: 待排序記錄數(shù)據(jù)量過大,需要借助外部存儲(chǔ)設(shè)備
排序的穩(wěn)定性:排序后有相同關(guān)鍵字的記錄順序不變就是穩(wěn)定的排序


插入類排序:
1.直接插入排序:將新加入的記錄的關(guān)鍵字與之前的記錄關(guān)鍵字從后往前比較,
?? ??? ??? ? ? 若較小,則向前比較,同時(shí)進(jìn)行比較的記錄后移一個(gè)位置,直到找到小于等于的關(guān)鍵字,插入在其后.?

實(shí)例代碼如下: (表內(nèi)操作)
void InsSort(int r[], int length){//r可以設(shè)置為結(jié)構(gòu)數(shù)組,這里認(rèn)為是數(shù)組?
?? ?int i,j;
?? ?for(i = 2; i < length; i++){ // i=2開始,i=1為第一個(gè)元素,認(rèn)為是子表,i=0設(shè)置為監(jiān)視哨?
?? ??? ?r[0] = r[i];//將待插入記錄存到監(jiān)視哨中,臨時(shí)保存?
?? ??? ?j = i - 1; ?//i為初始待插入記錄位置,i-1為需要比較的記錄位置
?? ??? ?while(r[0] < r[j]){
?? ??? ??? ?r[j+1] = r[j];
?? ??? ??? ?j--;
?? ??? ?}?
?? ??? ?r[j+1] = r[0];
?? ?}
}?

優(yōu)點(diǎn):算法簡(jiǎn)單,適用于記錄數(shù)目較少且基本有序
時(shí)間復(fù)雜度:O(n^2).

2.折半插入排序:類似于快排

示例代碼如下:
void BinSort(int r[], int length){
?? ?int i, x, j;
?? ?int low, high, mid;
?? ?for(i = 2;i <= length; i++){
?? ??? ?x = r[i];
?? ??? ?low = 1;
?? ??? ?high = i - 1;
?? ??? ?while(low < high){//Attention!不取等,書上是錯(cuò)的?
?? ??? ??? ?mid = (low + high) / 2;
?? ??? ??? ?if(x < r[mid])
?? ??? ??? ??? ?high = mid - 1;
?? ??? ??? ?else
?? ??? ??? ??? ?low = mid + 1;
?? ??? ?}
?? ??? ?for(j = i - 1; j >= low; j--)
?? ??? ??? ?r[j+1] = r[j];
?? ??? ?r[low] = x;?
?? ?}
}?

時(shí)間復(fù)雜度:O(n^2).
需要比較的次數(shù)最大為其折半判定樹的深度log2(n)

3.希爾排序:排序結(jié)果,基本有序;又稱縮小增量排序;將關(guān)鍵字序列分為若干個(gè)子序列,對(duì)子序列插入排序

void f1(int r[], int length, int d){//d為這一輪子序列長(zhǎng)度(增量)?
?? ?int i, j;
?? ?
?? ?for(i = 1+d; i <= length; i++){
?? ??? ?if(r[i] < r[i-d]){
?? ??? ??? ?r[0] = r[i];
?? ??? ??? ?for(j = i - d; j > 0 && r[j] > r[0]; j -= d){
?? ??? ??? ??? ?r[j + d] = r[j];
?? ??? ??? ?}//如果子序列后者的記錄關(guān)鍵字比前小,就復(fù)制前者到后者?
?? ??? ??? ?r[j + d] = r[0];//復(fù)制要交換的一個(gè)到適合的位置?
?? ??? ?}
?? ?}
}?
?
void f2(int r[], int length, int d[], int n){
?? ?for(i = 0; i < n; i++)//d[]為增量數(shù)組,n為該數(shù)組長(zhǎng)度 d[n-1] == 1;?
?? ??? ?f1(r, length, d[i]);
}
時(shí)間復(fù)雜度:O(n^1.5).
算法不是穩(wěn)定的 .


交換類排序:

1.冒泡排序(相鄰比序法):反復(fù)掃描記錄序列,依次交換逆序記錄的位置

void BubbleSort(int r[], int n){
?? ?bool change = true;
?? ?int i,j;
?? ?int x = 0;
?? ?for(i = 1; i < n && change; i++){
?? ??? ?change = false;
?? ??? ?for(j = 1; j <= n - i; j++){//一趟排序后最大的定了,在最后?
?? ??? ??? ?if(r[j]>r[j+1])
?? ??? ??? ?{
?? ??? ??? ??? ?x = r[j];
?? ??? ??? ??? ?r[j] = r[j+1];
?? ??? ??? ??? ?r[j+1] = x;
?? ??? ??? ??? ?change = true;
?? ??? ??? ?}
?? ??? ?}
?? ?}
}?

//下面這種簡(jiǎn)單些:上升法,不帶標(biāo)記?
void BubbleSort(int r[], int n){
?? ?int i, j, k;
?? ?
?? ?for(i = 0; i < n; i++){
?? ??? ?for(j = n - 2; j >= i; j--){
?? ??? ??? ?if(r[j] > r[j+1]){
?? ??? ??? ??? ?k = r[j];
?? ??? ??? ??? ?r[j] = r[j+1];
?? ??? ??? ??? ?r[j+1] = k;
?? ??? ??? ?}
?? ??? ?}
?? ?}?
}

時(shí)間的復(fù)雜度:O(n^2).?

2.快排:原理:一次性可以消除多個(gè)逆序來(lái)減少耗費(fèi)時(shí)間
找到一個(gè)劃分元,關(guān)鍵字小的移到前面,大的移到后面,遞歸在子序列中找出劃分元.直到子表長(zhǎng)度小于等于1

void QKSort(int r[], int low. int high){
?? ?if(low < high){
?? ??? ?pos = QKPass(r, low, high);//再次快排
?? ??? ?QKSort(r, low, pos -1);
?? ??? ?QKSort(r, pos +1, high);?
?? ?}
}?

一趟快速排序算法:?
int QKPass(int r[], int low, int high){
?? ?int x;
?? ?while(low < high){
?? ??? ?while(low < high && r[high] > x)
?? ??? ??? ?high--;
?? ??? ?if(low < high){
?? ??? ??? ?r[low] = r[high];
?? ??? ??? ?low++;
?? ??? ?}?? ?
?? ??? ?while(low < high && r[low] < x)
?? ??? ??? ?low++;
?? ??? ?if(low < high){
?? ??? ??? ?r[high] = r[low];
?? ??? ??? ?high--;
?? ??? ?}?? ??? ?
?? ?}
?? ?r[low] = x;
?? ?return low;
}
時(shí)間復(fù)雜度:O(nlog2(n))?


選擇類排序:

1.簡(jiǎn)單選擇排序:直接從數(shù)組中選擇最小的記錄和第一個(gè)記錄交換位置,循環(huán)

void SelectSort(int r[], int b){
?? ?int i, j, k;
?? ?int x;
?? ?
?? ?for(i = 1; i < n; i++){
?? ??? ?k = i;
?? ??? ?for(j = i+1; j <= n; j++){
?? ??? ??? ?if(r[j] < r[k])//選擇最小的記錄,得到在數(shù)組中的位置?
?? ??? ??? ??? ?k = j;
?? ??? ?}
?? ??? ?if(k != i){
?? ??? ??? ?x = r[i];
?? ??? ??? ?r[i] = r[k];
?? ??? ??? ?r[k] = x;
?? ??? ?}//交換位置?
?? ?}
}?
時(shí)間復(fù)雜度:O(n^2).

2.樹形選擇排序(錦標(biāo)賽排序):與簡(jiǎn)單選擇排序不同點(diǎn)是,占用空間更多,保留了之前的比較結(jié)果
每一個(gè)記錄看作葉子節(jié)點(diǎn),兩兩比較,選出最小的為雙親,進(jìn)一步遞歸向上,找出根,比較成功后,
該記錄對(duì)應(yīng)的葉子節(jié)點(diǎn)置為無(wú)窮;
進(jìn)一步兩兩比較重復(fù)上述過程,直到記錄全部輸出
時(shí)間復(fù)雜度:O(nlog2(n)).?


3.堆排序:排序過程中把向量中儲(chǔ)存的數(shù)據(jù)看作一顆完全二叉樹來(lái)進(jìn)行操作
重建堆:
?? ?大堆,篩選最大的元素出去,然后最后的元素補(bǔ)根節(jié)點(diǎn),調(diào)整堆使最大的元素在最上面?
void sift(Type r[], int k, int m){
?? ?//r[k...m]是以r[k]為根的完全二叉樹,調(diào)整r[k]使之滿足堆的性質(zhì)?
?? ?int i, j, t, x;
?? ?
?? ?t = r[k];
?? ?x = r[k].key;?
?? ?i = k;
?? ?j = 2 * k;//j指向t的左孩子
?? ?bool finished = false;
?? ?
?? ?while(j <= m && !finished){
?? ??? ?if(j + 1 <= m && r[j].key < r[j+1].key){
?? ??? ??? ?j++;
?? ??? ?}//得到左右孩子中記錄關(guān)鍵字較大的位置坐標(biāo)?
?? ??? ?if(x >= r[j].key) //如果滿足堆的性質(zhì),上面的比孩子大?
?? ??? ??? ?finished = true;
?? ??? ?else{
?? ??? ??? ?r[i] = r[j];
?? ??? ??? ?i = j;
?? ??? ??? ?j = 2 * i;
?? ??? ?}
?? ?}?
?? ?r[i] = t;
}?

建初堆:
void crt_heap(Type r[], int n)
{
?? ?//對(duì)r[]建立堆, n為數(shù)組長(zhǎng)度
?? ?int i;
?? ?for(i = n / 2; i >= 1; i--)//i指向最后一個(gè)非葉子節(jié)點(diǎn)?
?? ??? ?sift(r, i, n);?
?}?

堆排序算法:
void HeapSort(Type r[], int n)
{
?? ?crt_heap(r, n);
?? ?
?? ?for(i = n; ?i>= 2 ;--i){
?? ??? ?r[0] = r[1];
?? ??? ?r[1] = r[i];
?? ??? ?r[i] = r[0];//最后一個(gè)元素和第一個(gè)元素交換位置,把最大的換到最后面去,以此達(dá)到升序排列x?
?? ??? ?sift(r, 1, i-1);
?? ?}
?}?

時(shí)間復(fù)雜度:O(nlog2(n)).
算法是不穩(wěn)定的, 空間復(fù)雜度O(1) .

歸并類排序:將兩個(gè)或兩個(gè)以上的有序表合并成一個(gè)表

兩個(gè)有序子序列合并算法:?
void Merge(Type r1[], int low, int mid, int high, Type r2[])
{
?? ?//r1[low...mid]和r1[mid+1,..high]分別按照關(guān)鍵字有序排列 ,合并存放在r2[]中
?? ?int i, j, k;
?? ?i = low;
?? ?j = mid + 1;
?? ?k = low;
?? ?
?? ?while(i <= mid && j <= high){
?? ??? ?if(r1[i].key <= r1[j].key)
?? ??? ??? ?r2[k++] = r[i++];
?? ??? ?else
?? ??? ??? ?r2[k++] = r[j++];
?? ?}
?? ?while(i <= mid){
?? ??? ?r2[k++] = r1[i++];
?? ?}
?? ?while(j <= high){
?? ??? ?r2[k++] = r1[j++];
?? ?}
?}?

2-路歸并排序的遞歸算法:
void MSort(Type r1[], int low, int high, Type r3[])
{
?? ?//r1[low...high]排序后放在r3[low...high] 中, r2為輔助空間
?? ?Type *r2;
?? ?int mid;
?? ?
?? ?
?? ?r2 = (Type *)malloc(sizeof(Type) * (high - low + 1));
?? ?if(low == high) r3[low] = r1[low];
?? ?//這個(gè)是遞歸最終退出條件
?? ?else{//r1前半段放到r2前半段中,同理對(duì)于后半段,再將r2合并排序?
?? ??? ?mid = (low + high) / 2;
?? ??? ?MSort(r1, low, mid, r2);
?? ??? ?MSort(r1, mid + 1, high, r2);?
?? ??? ?Merge(r2, low, mid, high, r3);
?? ?}?
?? ?free(r2);
?}?

調(diào)用:
void MergeSort(Type r[], int n){
?? ?MSort(r, 1, n, r);
}?

分配類排序:核心是分配和收集,利用關(guān)鍵字的優(yōu)先級(jí)進(jìn)行排序的思想?

高位優(yōu)先排序:比如橋牌,先比較花色在比較面值;比如學(xué)號(hào),比較級(jí),院,班,號(hào);

低位優(yōu)先排序: 鏈?zhǔn)交鶖?shù)排序
思想:基于"分配"和"收集"的操作, 將單關(guān)鍵字轉(zhuǎn)化為多關(guān)鍵字排序
將鏈表作為存儲(chǔ)結(jié)構(gòu), 待排序記錄以指針相連,構(gòu)成鏈表;
分配:按照關(guān)鍵字取值分配記錄到鏈隊(duì)列相應(yīng)隊(duì)列中,每個(gè)隊(duì)列關(guān)鍵字取值相同
收集:按照關(guān)鍵字大小,從小到大,將隊(duì)列首尾相接連接成一個(gè)鏈表;
重復(fù)上述步驟..

定義:
//待排序記錄結(jié)點(diǎn)
typedef struct node{
?? ?int data;//比如說(shuō)一個(gè)三位數(shù)?
?? ?struct node *next;
}TNode;

//隊(duì)列首尾指針
typedef struct{
?? ?node *front;
?? ?node *rear;
}TPointer;?


//根據(jù)數(shù)組R[](已經(jīng)存在元素),構(gòu)建帶頭結(jié)點(diǎn)待排序記錄鏈表
TNode *create_list(int R[], int n){
?? ?
?? ?TNode *p, *ph;
?? ?//p為每一個(gè)存了記錄的結(jié)點(diǎn), ph為頭結(jié)點(diǎn)
?? ?ph = (TNode *)malloc(sizeof(TNode));
?? ?if(!ph) return NULL;?
?? ?ph->next = NULL;
?? ?
?? ?int i;
?? ?for(i = 0; i < n; i++){
?? ??? ?p = (TNode *)malloc(sizeof(TNode));
?? ??? ?if(!p) return NULL;
?? ??? ?
?? ??? ?p->data = R[i];
?? ??? ?//頭插法插入?
?? ??? ?p->next = ph->next;
?? ??? ?ph->next = p;
?? ?}
?? ?return ph;//返回頭結(jié)點(diǎn)?
}?

#define N 10
//分配算法,對(duì)三位數(shù)的記錄序列按照關(guān)鍵字低位排序分配?
void dispatch(TNode *ph, TPointer *Q, int d){?? ?
?? ?//ph存記錄, Q隊(duì)列:存指針,d根據(jù)關(guān)鍵字到那一趟取值不同?? ?
?? ?TNode *p = NULL;//作為輔助空間拆分ph?
?? ?int i, idx;
?? ?
?? ??
?? ?//初始化Q
?? ?for(i = 0; i < N; i++){
?? ??? ?Q[i].front = NULL;
?? ??? ?Q[i].rear = NULL;?
?? ?}?
?? ?
?? ?p = ph->next;
?? ?if(p){
?? ??? ?ph->next = p->next;
?? ??? ?p->next = NULL;
?? ?}//第一個(gè)記錄被單獨(dú)拆到p里面
?? ?
?? ?while(p){
?? ??? ?idx = p->data;
?? ??? ?for(i = 0; i < d; i++)
?? ??? ??? ?idx = idx / N;
?? ??? ?//第一趟排序,d = 0
?? ??? ?idx = idx % N;
?? ??? ?
?? ??? ?//根據(jù)關(guān)鍵字分配到Q中
?? ??? ?if(Q[idx].front = NULL){
?? ??? ??? ?Q[idx].front = p;
?? ??? ??? ?Q[idx].rear = p;
?? ??? ?}?
?? ??? ?else{//尾插法?
?? ??? ??? ?Q[idx].rear->next = p;
?? ??? ??? ?Q[idx].rear = p;
?? ??? ?}
?? ??? ?p = ph->next;
?? ??? ?if(p){//拆,直到拆完?
?? ??? ??? ?ph->next = p->next;
?? ??? ??? ?p->next = NULL;
?? ??? ?}
?? ?}?
}

void collect(TNode *ph, TPointer *Q){
?? ?TNode *p;
?? ?int i;
?? ?//ph為頭結(jié)點(diǎn),最終可以傳出去
?? ?
?? ?for(i = 0; !Q[i].front; i++)
?? ??? ?;//找出第一個(gè)隊(duì)列中非空結(jié)點(diǎn)
?? ?ph->next = Q[i].front;
?? ?p = Q[i].rear;
?? ?i++;
?? ?
?? ?for(; i < N; i++){
?? ??? ?if(Q[i].front){
?? ??? ??? ?p->next = Q[i].front;
?? ??? ??? ?p = Q[i].rear;//注意的是Q[i]內(nèi)部的結(jié)點(diǎn)是連接好的?
?? ??? ?}
?? ?}
?? ?p->next = NULL;
}?

void list_sort(int *R, int n){
?? ?int i;
?? ?TNode *ph, *p;
?? ?TPointer Q[N];
?? ?int m = max(R, n);//最大關(guān)鍵字?
?? ?
?? ?ph = create_list(R, n);
?? ?
?? ?for(i = 0; m; i++, m /= N){
?? ??? ?dispatch(ph, Q, i);
?? ??? ?collect(ph, Q);
?? ?}
?? ?for(i = 0, p = ph->next; p; p = p->next){
?? ??? ?R[i] = p->data;//復(fù)制到數(shù)組最終輸出?
?? ?}
?? ?free(ph);
}

總結(jié)

以上是生活随笔為你收集整理的第三个一千行+500行总结-数据结构C复习--知识点总结3--七到九章的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。