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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

icoding复习7, 8

發布時間:2023/12/4 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 icoding复习7, 8 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

icoding復習7 哈希,AVL 查找
必考點!!!?
1. 哈希表創建
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;
// 創建大小為hash_size的哈希表,創建成功后返回HashTable類型的指針,否則返回NULL。
HashTable *create_hash(int hash_size);
哈希表相關說明:

HASH_RESULT 類型為相關函數的返回類型
HashEntry 為哈希表所保存元素(即鍵值對 《key, value》)類型
HashTable 為哈希表,其中 bucket 指向大小為size的、元素類型為 HashEntry*的指針數組
哈希表采用鏈地址法處理沖突
請實現 create_hash 函數,創建指定大小的哈希表。

#include
#include
#include "hash.h"

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

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

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

HASH_RESULT hash_add_int(HashTable *table, const char *key, int value){
?? ?int i = hash_string(key) % table->size;
?? ?HashEntry *p;
?? ?
?? ?p = table->bucket[i];
?? ?
?? ?if(!p){//該關鍵字不存在?
?? ??? ?p = (HashEntry *)malloc(sizeof(HashEntry)); // 判空略
?? ??? ?strcpy(p->key.str_value, key);
?? ??? ?p->value.int_value = value;?
?? ??? ?table->bucket[i] = p;
?? ??? ?
?? ??? ?return HASH_ADDED;
?? ?}
?? ?//關鍵字存在,先判斷關鍵字是否相等,再判斷值;如果關鍵字不等那么最后還要鏈地址添加
?? ?while(p){
?? ??? ?if(strcmp(p->key.str_value, key)){
?? ??? ??? ?if(p->value.int_value == value){
?? ??? ??? ??? ?return HASH_ALREADY_ADDED;
?? ??? ??? ?}
?? ??? ??? ?else{
?? ??? ??? ??? ?p->value.int_value = value;
?? ??? ??? ??? ?return HASH_REPLACED_VALUE;
?? ??? ??? ?}
?? ??? ?}
?? ??? ?else
?? ??? ??? ?p = p->next;
?? ?}?
?? ?HashEntry *q = (HashEntry *)malloc(sizeof(HashEntry)); // 判空略
?? ?q->key = (char *)malloc(sizeof(char) *strlen(key));//判空類似前面的?
?? ?
?? ?strcpy(q->key.str_value, key);
?? ?q->value.int_value = value;
?? ?p->next = q;
?? ?q->next = NULL;
?? ?return HASH_ADDED;?
}

3. AVL添加
平衡二叉樹,是一種二叉排序樹,其中每個結點的左子樹和右子樹的高度差至多等于1。
它是一種高度平衡的二叉排序樹。現二叉平衡樹結點定義如下:

typedef struct node
{
? ? int val;
? ? struct node *left;
? ? struct node *right;
? ? struct node *parent;
? ? int height;
} node_t;
//請實現平衡二叉樹的插入算法:

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

#include
#include
#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新插入結點元素值,height高度!!!?
//定義查找過程中出現的距離插入結點最近的平衡因子不為零的結點A
//定義A的孩子結點為B,需要旋轉的結點
//定義插入節點為s,s的值為val
//平衡因子:左子樹減去右子樹深度?

?? ?node_t *s, *A, *B, *C, *p, *fp;
?? ?//依次:插入點, 失衡點(也可能是旋轉點),旋轉點,旋轉點(也可能是插入點=s),動點,跟蹤點
?? ?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;
?? ?
?? ?//類似于指針跟蹤技術,p為動指針,A為跟蹤指針?
?? ?A = root; A->parent = NULL;
?? ?p = root; p->parent = NULL;
?? ?
?? ?//找出A?
?? ?if(!p)
?? ??? ?root = s;
?? ?else{
?? ??? ?while(p){
?? ??? ??? ?//先找出最近的A->height!=0的結點, 就是最后的失衡點
?? ??? ??? ?i = get_height(p->left) - get_height(p->right);?
?? ??? ??? ?if(i){
?? ??? ??? ??? ?A = p;
?? ??? ??? ??? ?A->parent = p->parent;
?? ??? ??? ?}
?? ??? ??? ?//fp跟蹤p,因為下一步p會往下移動,p最終指向s的那一層?
?? ??? ??? ?fp = p;
?? ??? ??? ?if(val < p->val)
?? ??? ??? ??? ?p = p->left;
?? ??? ??? ?else
?? ??? ??? ??? ?p = p->right;
?? ??? ??? ?}//p最終指向NULL就退出循環?? ??
?? ?}?
?? ?
?? ?//插入, 此時fp是p的前一個結點,p指向空?
?? ?if(val < fp->val)
?? ??? ?fp->left = s;
?? ?else
?? ??? ?fp->right = s;
?? ??? ?
?? ?//確定旋轉結點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的高度沒有++的 , 初始值賦為1?
?? ??? ?
?? ?
?? ?//調整完高度就修改結點和指針, 首先需要判斷失衡類型
?? ?//分為LL,LR,RR,RL
?? ?//結點A,B平衡因子在修改指針的過程中會變化,但是路徑上的結點不會
?? ?//指針修改包括s結點指針和原來雙親結點指針?
?? ?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作為旋轉結點
?? ??? ?//先改結點指針, 此時s插入在B的左子樹下, 原來可以認為B左右子樹,A右子樹均為空
?? ??? ?A->left = B->right;
?? ??? ?B->right = A;
?? ??? ?
?? ??? ?//考慮原來A結點的指針,改成B后相應的指針也要改變,下面同理
?? ??? ?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
?? ??? ?//此時認為C的左右子樹空,B逆時針旋轉,A順時針旋轉, s插入C的左子樹或者右子樹?
?? ??? ?//如果C結點也是空,也就是說B右子樹空,那么直接插入C=s為B右子樹,此時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一樣,畫圖來看就好
?? ??? ?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;
}

icoding復習8 堆排?

1. 堆輔助函數

二叉堆是完全二叉樹或者是近似完全二叉樹。二叉堆有兩種:最大堆和最小堆。

最大堆(大頂堆):父結點的鍵值總是大于或等于任何一個子節點的鍵值,即最大的元素在頂端;
最小堆(小頂堆):父結點的鍵值總是小于或等于任何一個子節點的鍵值,即最小的元素在頂端。
二叉堆子結點的大小與其左右位置無關。
二叉堆一般用數組來表示。例如,根節點在數組中的位置是0,第n個位置的子節點分別在2n+1和 2n+2。
因此,第0個位置的子節點在1和2,1的子節點在3和4。以此類推。這種存儲方式便于尋找父節點和子節點。
在二叉堆上可以進行插入節點、刪除節點、取出值最小的節點、減小節點的值等基本操作。

“最小堆”的定義如下:
typedef struct _otherInfo
{
? ? int i;
? ? int j;
}OtherInfo;

typedef struct _minHeapNode
{
? ? int value;
? ? OtherInfo otherInfo;
}MinHeapNode, *PMinHeapNode;

typedef struct _minPQ {
? ? PMinHeapNode heap_array; // 指向堆元素數組
? ? int heap_size; // 當前堆中的元素個數
? ? int capacity; ?//堆數組的大小
}MinHeap, *PMinHeap;
請實現最小堆的四個輔助函數:

int parent(int i); //返回堆元素數組下標為 i 的結點的父結點下標
int left(int i); ?//返回堆元素數組下標為 i 的結點的左子結點下標
int right(int i); ?//返回堆元素數組下標為 i 的結點的右子結點下標
void swap_node(MinHeapNode *x, MinHeapNode *y); ?//交換兩個堆元素的值


!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
重點區別
1. PMinHeapNode heap_array
2. MinHeapNode *heap_array
3. MinHeapNode heap_array[capacity]//三者等價,前兩者沒分配空間

對于heap_array[i].value,記得點運算符, 因為這個不是指針了!!!!!
?

#include
#include
#include "minbinheap.h" // 請不要刪除,否則檢查不通過

int parent(int i){
?? ?return (i - 1) / 2;?
}
int left(int i){
?? ?return 2*i+1;
}
int right(int i){
?? ?return 2*i+2;
}
void swap_node(MinHeapNode *x, MinHeapNode *y){
?? ?int value;
?? ?int i, j;
?? ?
?? ?value = y->value;
?? ?i = y->otherInfo.i;
?? ?j = y->otherInfo.j;
?? ?
?? ?y->value = x->value;
?? ?y->otherInfo.i = x->otherInfo.i;
?? ?y->otherInfo.j = x->otherInfo.j;
?? ?
?? ?x->value = value;
?? ?x->otherInfo.i = i;
?? ?x->otherInfo.j = j;
?? ?
?? ?return;
}

2. 堆初始化
請實現最小堆的初始化函數:

void init_min_heap(PMinHeap pq, int capacity);
其中 pq指向堆,capacity為堆元素數組的初始化大小。

void init_min_heap(PMinHeap pq, int capacity){//小根堆, 小的在上面?
//題目沒有明確?
//?? ?pq = (PMinHeap)malloc(sizeof(MinHeap));
//?? ?if(!pq) return;
?? ?
?? ?if(!(pq->heap_array = (PMinHeapNode)malloc(sizeof(MinHeapNode) * capacity))){
?? ??? ?free(pq); return;
?? ?}
?? ?pq->capacity = capacity;
?? ?pq->heap_size = 0;
?? ?//return;
}


3. 堆化
請實現最小堆的“堆化”函數:
void min_heapify(PMinHeap pq, int i);
其中 pq指向堆,i 為堆元素在數組中的下標。該函數假設元素i對應的子樹都已經是最小堆
(符合最小堆的要求),但元素i為根的子樹并不是最小堆,
min_heapify將對元素i及其子樹的各結點進行調整,使其為一個最小堆。

void min_heapify(PMinHeap pq, int i){
?? ?int j = parent(i);
?? ?//if(pq->heap_array[i].value > pq->heap_array[j].value) return;
?? ?for(; j >= 0 && pq->heap_array[i].value > pq->heap_array[j].value; i = j, j = parent(i))
?? ??? ?swap_node(&pq->heap_array[i], &(pq->heap_array[j]));
}

void min_heapify(PMinHeap pq, int i){//一行?
?? ?for(int j = parent(i); j >= 0 && pq->heap_array[i].value > pq->heap_array[j].value; i = j, j = parent(i))swap_node(&(pq->heap_array[i]), &(pq->heap_array[j]));}
?? ?
?? ?
4. 堆元素插入
請實現最小堆的元素插入函數:

bool heap_insert_value(PMinHeap pq, int value);
其中 pq指向堆,value 為要插入的堆元素。

bool heap_insert_value(PMinHeap pq, int value){//小根堆,子樹關鍵字大于等于根的關鍵字?
?? ?//if(pq->heap_size == pq->capacity - 1) return false;
?? ?
?? ?int i, j;
?? ?i = pq->heap_size;
?? ?j = parent(i);
?? ?pq->heap_array[i].value = value;
?? ?while(i){
?? ??? ?if(value < pq->heap_array[j].value){
?? ??? ??? ?swap_node(&(pq->heap_array[i]), &(pq->heap_array[j]));
?? ??? ??? ?i = j;
?? ??? ??? ?j = parent(i);
?? ??? ?}
?? ??? ?else{
?? ??? ??? ?pq->heap_size++;
?? ??? ??? ?return true;
?? ??? ?}
?? ?}?? ?
}

5. 數組合并
假設有 n 個長度為 k 的已排好序(升序)的數組,請設計數據結構和算法,
將這 n 個數組合并到一個數組,且各元素按升序排列。即實現函數:

?void merge_arrays(const int* arr, int n, int k, int* output);
其中 arr 為按行優先保存的 n 個長度都為 k 的數組,output 為合并后的按升序排列的數組,大小為 n×k。

時間要求(評分規則),當 n > k 時:
滿分:時間復雜度不超過 O(n×k×log(n))
75分:時間復雜度不超過 O(n×k×log(n)×k)
59分:其它,如:時間復雜度為 O(n2×k2) 時。

#include
#include
//建立大根堆(大的在上面) ?
void build_bigroot(int *a, int i, int size){
//參數說明:a傳入的數組,i待排序元素開始位置,size數組元素個數(長度)
?? ?int j, s;
?? ?//j是i的孩子指針,s暫存排序的元素
?? ?
?? ?//不設監視哨,所以從'0'(i)開始排序,孩子為2*i+1?
?? ?j = 2 * i + 1;
?? ?s = a[i];
?? ?
?? ?while(j < size){//可以設置bool變量測試是否篩選完畢,減小時間復雜度?
?? ?//不可以取等哈 ,0開始的
?? ?
?? ??? ?//存在右子樹并且右子樹更大,那么篩選右子樹?
?? ??? ?if(j + 1 < size && a[j+1] > a[j])
?? ??? ??? ?j++;?
?? ??? ?
?? ??? ?if(s >= a[j])
?? ??? ??? ?break;
?? ??? ?else{//如果大的記錄在下,那么上浮?
?? ??? ??? ?a[i] = a[j];
?? ??? ??? ?i = j;
?? ??? ??? ?j = 2 * i + 1;
?? ??? ?}?
?? ?}
?? ?//最后把篩選完成后的數據放在合適位置
?? ?a[i] = s;?
}

void merge_arrays(const int *arr, int n, int k, int* output){
?? ?//說明一下arr為const int類型,不能改動,所以只好浪費時空復制出來在變動
?? ?int i, size, x;
?? ?size = n * k;
?? ?int a[size];
?? ?//大根堆是大的在上,沒有什么其他要求.堆排后大的放大到最后,形成升序排列的小根堆?
?? ?
?? ?for(i= 0; i < size; i++)
?? ??? ?a[i] = arr[i];
?? ?//建立大根堆?
?? ?for(i = size / 2 -1; i >= 0; i--)
?? ??? ?build_bigroot(a, i , size);
?? ?//堆排?
?? ?for(i = size - 1; i >=1; i--){
?? ??? ?x = a[0];
?? ??? ?a[0] = a[i];
?? ??? ?a[i] = x;
?? ??? ?build_bigroot(a, 0, i);
?? ?}?
?? ?for(i = 0; i < size; i++)
?? ??? ?output[i] = a[i];
}?

總結

以上是生活随笔為你收集整理的icoding复习7, 8的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。