第二个一千行总结-数据结构C复习--知识点总结2--五到七章
第五章 數組與廣義表
n維數組看作數據元素為n-1維數組的線性表
數組地址計算:略
特殊矩陣壓縮:
三角矩陣;三對角矩陣(帶狀矩陣);
稀疏矩陣:存儲數據總量小于百分之三十
稀疏矩陣用三元組(行,列,值)儲存,定義如下:
typedef struct{
?? ?int row, col;//行,列?
?? ?int e;
}Triple;
typedef struct{
?? ?Triple data[MAX+1];
?? ?int m, n, len;//行,列,數據總個數?
}TSMtrix;
普通雙for循環算法
void TransMatrix(int a[m][n], b[m][n]){
?? ?int i, j;
?? ?
?? ?for(i = 0; i < m; i++)
?? ??? ?for(j = 0; j < n; j++)
?? ??? ??? ?b[j][i] = a[i][j];?? ?
}?
稀疏矩陣遞增轉置法
void TransposeTSMatrix(TSMatrix A, TSMatrix *B){
?? ?int i, j, k;
?? ?
?? ?B->m = A.n; B->n = A.m; B->len = A.len;
?? ?//多次掃描,找到A列中對應B中的行的元素,一共掃描A.n次?
?? ?if(B->len){
?? ??? ?j = 1;
?? ??? ?for(k = 1;k <= A.n;k++)//A.n為列數
?? ??? ??? ?for(i=0 ;i < A.len;i++) ? ? ? ? ? ? ??
?? ??? ??? ??? ?if(A.data[i].col == k)
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?B->data[j].row = A.data[i].col;
?? ??? ??? ??? ??? ?B->data[j].col = A.data[i].row;
?? ??? ??? ??? ??? ?B->data[j].e = A.data[i].e;
?? ??? ??? ??? ??? ?j++;
?? ??? ??? ??? ?}
?? ??? ??? ?
?? ?}
}?
//一次快速定位轉置法
void FastTransposeTSMatrix(TSMatrix A, TSMatrix *B) {
?? ?int col, i, j ,k;
?? ?//值得注意的是Triple定義的數組data[]保存的是存在元素(非0元素),值為零的不存?
?? ?int num[MAXSIZE],position[MAXSIZE];
?? ?
?? ?B->m = A.n; B->n = A.m; B->len = A.len;
?? ?if(B->len){
?? ??? ?num[] = {0};
?? ??? ?//循環清0也可以
?? ??? ?for(t = 1;t <= A.len;t++)
?? ??? ??? ?num[A.data[t].col]++;//統計第col列的數據個數?
?? ??? ??? ?
?? ??? ?position[1] = 1;
?? ??? ?for(col = 2;col<=A.len;col++)//根據num每一列個數得到每一個新列第一個元素的位置?
?? ??? ??? ?position[col] = position[col-1]+num[col-1]; //position為第幾個元素
?? ??? ??? ??
?? ??? ?for(p = 1;p ?? ??? ?{
?? ??? ??? ?col = A.data[p].col;?
?? ??? ??? ?q = position[col];//找到該列第一個元素的位置?
?? ??? ??? ?B->data[q].row = A.data[p].col;
?? ??? ??? ?B->data[q].col = A.data[p].row;
?? ??? ??? ?B->data[q].e = A.data[p].e;
?? ??? ??? ?position[col]++;
?? ??? ??? ?//下一個列號為col的非零元素再B中存放位置?
?? ??? ?}
?? ?}
}
十字鏈表?
typedef ElemType int
typedef struct OLNode
{
?? ?int col, row;
?? ?ElemType value;
?? ?struct OLNode *right, *down;?
}OLNode, *OLink;
typedef struct
{
?? ?OLink *row_head, *col_head;//注意這個是行列頭指針鏈表的指針數組?
?? ?int m, n, len;?? ??? ??? ??? ?//行列長度?
}CrossList;
//建立十字鏈表
bool CreateCrossList(CrossList *M){
?? ?//先輸入矩陣M的相關信息?
?? ?//為指針數組分配空間并且初始化
?? ?//輸入十字鏈表每個節點的相關信息
?? ?//判斷是否輸入正確
?? ?//正確則進行創建結點并且插入鏈表
?? ?int m, n, len;
?? ?int col, row;
?? ?ElemType value;
?? ?int i;
?? ?OLink *q,*p;
?? ??
?? ?
?? ?scanf(&m, &n, &len);
?? ?M->len = len; M->m = m; M->n = n;
?? ?
?? ?if(!(M->row_head = (* OLink)malloc(m * sizeof(OLink)))) return false;
?? ?if(!(M->col_head = (* OLink)malloc(n * sizeof(OLink)))) return false;
?? ?//以下可以直接寫M->row_head[ ] = NULL;
?? ?for(i = 0; i < m; i++)
?? ??? ?M->row_head[i] = NULL;
?? ?for(i = 0;i < n; i++)
?? ??? ?M->col_head[i] = NULL;
?? ?
?? ?for(scanf(&row, &col, &value); row != -1; scanf(&row, &col, &value))
?? ?{
?? ??? ?if(!(p = (OLNode *)malloc(sizeof(OLNode)))) return false;
?? ??? ?p->col = col;
?? ??? ?p->row = row;
?? ??? ?p->value = value;
?? ??? ?//先插行再插列互相不干擾
?? ??? ?if(M->row_head[row] == NULL)?
?? ??? ??? ?M->row_head[row] = p;
?? ??? ?else{
?? ??? ??? ?q = M->row_head[row];
?? ??? ??? ?while(q->right && q->right->row < row)
?? ??? ??? ??? ?q = q->right;
?? ??? ??? ?//q此時指向該行鏈表最后一個元素
?? ??? ??? ?//類似與尾插?
?? ??? ??? ?p->right = q->right;
?? ??? ??? ?q->right = p;
?? ??? ?}
?? ??? ?if(M->col_head[col] == NULL)
?? ??? ??? ?M->col_head[col] = p;
?? ??? ?else{
?? ??? ??? ?q = M->col_head[col];
?? ??? ??? ?while(q->down && q->down->col < col){
?? ??? ??? ??? ?q = q->down;
?? ??? ??? ?}
?? ??? ??? ?p->down = q->down;
?? ??? ??? ?q->down = p;
?? ??? ?}
?? ?}
}?
廣義表:遞歸定義, 可以為無限序列(線性表為有限序列).表頭為第一個元素,其余為表尾.
定義:
typedef enum{
?? ?ATOM, LIST
}Elemtag;//atom為原子結點標志,list為表結點標志
typedef struct GLNode{
?? ?ElemTag tag;
?? ?
?? ?union{//以下表明二選一?
?? ??? ?AtomType atom;
?? ??? ?struct{
?? ??? ??? ?struct GLNode *hp, *tp;
?? ??? ?}htp;
?? ?}atom_htp;
}GLNode , *GList;
廣義表操作:略
第六章: 樹與二叉樹!!!!!!!!!!!
定義:根,子樹,結點,度,高度(深度), 分支結點, 葉子節點, 森林, 孩子.兄弟.祖先.堂兄弟.子孫.雙親結點, 前/后輩.
?樹的圖解表示法?
?1.樹形表示法(倒置樹結構)
?2.文氏圖表示法
?3.廣義表示形式(嵌套括號表示法)
?4.凹入表示法?? ?
?
二叉樹!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
性質:第i層至多2^(i-1)個結點; 前k層至多2^(k-1)個結點.
葉子結點為n,度數為2結點為m,則n = m + 1.?
區別:!!!滿二叉樹和完全二叉樹
完全二叉樹為:其深度下的1~n的位置序號分別與等高的滿二叉樹一一對應. 其深度計算log2(n)向下取整+1
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?//相當于python里面的floor(log2(n)) log2(7)+1= 3
存儲結構:
順序存儲結構:按照結點的層序編號以此存儲到數組(向量)對應位置
鏈式存儲結構:
定義如下:
typedef DataType int
typedef struct Node{
?? ?DataType data;
?? ?struct Node *LChild;
?? ?struct Node *RChild;
}BiTNode, *BiTree;?
必考點!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!二叉樹的遍歷!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
遍歷規則:大致按照左中右,然后先/中/后序列代表著訪問根的先后順序,先序就先訪問?
先序遍歷:先遍歷根,再左子樹,再右子樹.
中序遍歷:先遍歷左子樹,再根,再右子樹.
后序遍歷:...
應用廣泛:表達式求值-->前綴表達式為波蘭表達式, 后綴表達式為逆波蘭表達式,后綴表達式易于求值
略
遞歸算法:
先/中/后序遍歷只是訪問根結點先后順序不一樣而已
//二叉樹的遍歷
//先序遍歷 DLR?
void PreOrder(BiTree root){
?? ?if(root != NULL){
?? ??? ?Visit(root->data);
?? ??? ?PreOrder(root->LChild);
?? ??? ?PreOrder(root->RChild);
?? ?}
}
//中序遍歷 LDR?
void InOrder(BiTree root){
?? ?if(root != NULL){
?? ??? ?InOrder(root->LChild);
?? ??? ?Visit(root->data);
?? ??? ?InOrder(root->RChild);
?? ?}
}
//后序遍歷 LRD
void PostOrder(BiTree root){
?? ?if(root != NULL){
?? ??? ?PostOrder(root->LChild);
?? ??? ?PostOrder(root->RChild);
?? ??? ?Visit(root->data);?
?? ?}
}
//輸出二叉樹中的結點
void PreOrder(BiTree root){
?? ?if(root != NULL){
?? ??? ?printf(root->data);
?? ??? ?PreOrder(root->LChild);
?? ??? ?PreOrder(root->RChild);
?? ?}
}
//輸出二叉樹中的葉子結點?
//先序遍歷
void PreOrder(BiTree root){
?? ?if(root!= NULL){
?? ??? ?if(root->LChild == NULL && root->RChild == NULL)
?? ??? ??? ?printf(root->data);
?? ??? ?PreOrder(root->LChild);
?? ??? ?PreOrder(root->RChild);
?? ?}
}?
//統計葉子節點的數目
//法1
//設置全局變量!!!!
int LeafCount = ?0;
void leaf(BiTree root)
{
?? ?leaf(root->LChild);
?? ?leaf(root->RChild);
?? ?if(root->LChild ==NULL && root->RChild == NULL){
?? ??? ?LeafCount++;
?? ?}
?}?
?
?//法2 分治算法 這個有點妙!?
int leaf(BiTree root)
{
?? ?if(root == NULL)
?? ??? ?LeafCount = 0;
?? ?else if(root->LChild == NULL || root->RChild == NULL){
?? ??? ?LeafCount++;
?? ?}?
?? ?else
?? ??? ?LeafCount = leaf(root->LChild) + leaf(root->RChild);
?? ?return LeafCount;
?}?
?
//建立二叉樹鏈表方式儲存二叉樹
//擴展先序遍歷方式創建二叉樹鏈表
原理:一棵樹先序遍歷得到結點的所有值;那么一堆值根據先序遍歷得到樹?
void CreatBiTree(BiTree *bt){
?? ?char ch;
?? ?ch = getchar();
?? ?
?? ?if(ch == '.')
?? ??? ?*bt = NULL;
?? ?else{
?? ??? ?*bt = (BiTree) malloc(sizeof(BiNode));
?? ??? ?(*bt)->data = ch;
?? ??? ?CreateBiTree(&(*bt)->LChild) ;
?? ??? ?CreateBiTree(&((*bt)->RChild);
?? ?}
}?
//求二叉樹的高度
//后序遍歷, 求高度, 遞歸
int PostTreeDepth(BiTree bt)
{
?? ?int hl, hr, max;
?? ?if(bt != NULL){
?? ??? ?hl = PostTreeDepth(bt->LChild);
?? ??? ?hr = PostTreeDepth(bt->RChild);
?? ??? ?max = hl > hr ? hl : hr;//三元運算符?
?? ??? ?return max +1 ;
?? ?}
?? ?else
?? ??? ?return 0;
?}?
?
//先序遍歷實現
int depth = 0;
void PreTreeDepth(BiTree bt, int h){
?? ?if(bt != NULL){
?? ??? ?if(h > depth)?
?? ??? ??? ?depth = h;
?? ??? ?PreTreeDepth(bt->LChild, h+1);
?? ??? ?PreTreeDepth(bt->RChild, h+1);
?? ?}
}
!!!!!!!!!!!!!!!!!!!!!!!!!!!!二叉樹的層次遍歷算法!!!!!!!!!!!!!很可能大題
void LevelOrder(BiTree bt){
?? ?BiTree Queue[MAX]; ? ? ? ? ? ?//將隊列與二叉樹結合, 重點!!!!
?? ?int front, rear;
?? ?
?? ?if(bt == NULL) return;
?? ?front = rear = 0;
?? ?
?? ?Queue[rear] = bt;//根節點入隊,隊尾入隊哈!
?? ?rear++;//尾指針移走
?? ?
?? ?//當front!=rear即隊列不為空
?? ?while(rear != front){
?? ??? ?printf("%d", Queue[front]);//visit(xxx);//訪問剛剛出隊的元素?
?? ??? ?if(Queue[front]->LChild){
?? ??? ??? ?Queue[rear] = Queue[front]->LChild;//存在左孩子則入隊?
?? ??? ??? ?rear++;?
?? ??? ?}
?? ??? ?if(Queue[front]->RChild){
?? ??? ??? ?Queue[rear] = Queue[front]->RChild;
?? ??? ??? ?rear++;?
?? ??? ?}
?? ??? ?front++;//出隊的最后操作?
?? ?}?
}?
//基于棧的遞歸消除
//中序遍歷二叉樹的非遞歸算法
void inorder(BiTree root){
?? ?Stack s[m];
?? ?int top = 0;
?? ?BiTNode *p;
?? ?
?? ?p = root;
?? ?
?? ?do{
?? ??? ?while(p != NULL){
?? ??? ??? ?if(top > m)?
?? ??? ??? ??? ?return;
?? ??? ??? ??? ?// 棧滿
?? ??? ??? ?top++;
?? ??? ??? ?s[top] = p;
?? ??? ??? ?p = p->LChild;
?? ??? ??? ?//遍歷左子樹?
?? ??? ?}
?? ??? ?if(top != 0){//棧空為0?
?? ??? ??? ?p = s[top];
?? ??? ??? ?top--;
?? ??? ??? ?Visit(p->data);
?? ??? ??? ?p = p->RChild;
?? ??? ?}
?? ??? ?
?? ?}while(p != NULL || top != 0);
?? ?//當前結點存在則入棧, 然后遍歷左子樹
?? ?//不在, 退棧, 訪問右子樹?
}?
//法2
//中序遍歷非遞歸算法
void Inorder(BiTree root)
{
?? ?Stack s;
?? ?InitStack(&s);
?? ?BiTNode *p = root;
?? ?
?? ?while(p != NULL || !IsEmpty(S))
?? ?{//棧空, p指向NULL, 結束?
?? ??? ?if (p){
?? ??? ??? ?Push(&S, p);
?? ??? ??? ?p = p->LChild;
?? ??? ?}
?? ??? ?else
?? ??? ?{
?? ??? ??? ?Pop(&s, &p);
?? ??? ??? ?Visit(p->data);
?? ??? ??? ?p = p->RChild;
?? ??? ?}
?? ?}
?}?
?
//后序遍歷二叉樹的非遞歸算法
void PostOrder(BiTree root){
?? ?BiTNode *p, *q;
?? ?Stack S;
?? ?q = NULL;
?? ?p = root;
?? ?Init(&Stack);
?? ?
?? ?while(p != NULL || !IsEmpty(S)){
?? ??? ?if(p){
?? ??? ??? ?Push(&S, p);
?? ??? ??? ?p = p->LChild;
?? ??? ?}?
?? ??? ?else{
?? ??? ??? ?GetTop(&S, &p);
?? ??? ??? ?if(p->RChild == NULL || p->RChild == q){//第二個條件判斷是否也已經遍歷過.類似于指針跟蹤技術?
?? ??? ??? ??? ?visit(p->data);
?? ??? ??? ??? ?q = p;
?? ??? ??? ??? ?Pop(&S, &p);
?? ??? ??? ??? ?p = NULL;
?? ??? ??? ?}
?? ??? ??? ?else
?? ??? ??? ??? ?p = p->RChild;
?? ??? ?}
?? ?}
}?
//后序遍歷法2
void PostOrder(BiTree root){
?? ?Stack st;
?? ?BiTNode *p, *q, *r;
?? ?p = root;
?? ?InitStack(&st);
?? ?bool flag;
?? ?
?? ?do{
?? ??? ?while(p != NULL){
?? ??? ??? ?Push(&st, &p);
?? ??? ??? ?p = p->LChild;
?? ??? ?}
?? ??? ?r = NULL;
?? ??? ?flag = true;
?? ??? ?
?? ??? ?while(!IsEmpty(st) && flag){
?? ??? ??? ?GetTop(&st, &p);
?? ??? ??? ?if(p->RChild == r){
?? ??? ??? ??? ?Visit(p->data);
?? ??? ??? ??? ?Pop(&st, &p);
?? ??? ??? ??? ?r = p;
?? ??? ??? ?}
?? ??? ??? ?else{
?? ??? ??? ??? ?p = p->LChild;
?? ??? ??? ??? ?flag = false;
?? ??? ??? ?}
?? ??? ?}
?? ??? ?
?? ?}while(!IsEmpty(st));
?? ?DestroyStack(st);
}?
線索二叉樹:
原理:n個結點的二叉樹有2n個鏈域,而只有n-1條邊(離散),n+1個鏈空浪費?
// LChild Ltag data Rtag RChild
typedef struct Node{
?? ?int data;
?? ?struct Node *LChild;
?? ?struct Node *RChild;
?? ?
?? ?int Rtag;//0,指示結點的右孩子,1指示結點的遍歷后繼?
?? ?int Ltag;//0,指示結點的左孩子,1指示結點的遍歷前驅?
}BiTNode, *BiTree;
void Inthread(BiTree root){
?? ?if(root != NULL){
?? ??? ?Inthread(root->LChild);//線索化左子樹?
?? ??? ?if(root->LChild == NULL){
?? ??? ??? ?root->Ltag = 1;
?? ??? ??? ?root->LChild = pre;
?? ??? ?}
?? ??? ?if(pre != NULL && pre->RChild ==NULL){
?? ??? ??? ?pre->RChild = root;
?? ??? ??? ?pre->Rtag = 1;
?? ??? ?}
?? ??? ?pre = root;
?? ??? ?Inthread(root->RChild);
?? ?}
}?
//在中序線索樹中找結點前驅
BiTNode *InPre(BiTNode *p){
?? ?BiTNode *q, *pre;
?? ?if(p->Ltag == 1)?
?? ??? ?pre = p->LChild;
?? ?else{
?? ??? ?//在p的左子樹中找最右下端點
?? ??? ?for(q = p->LChild; q->Rtag == 0; q = q->RChild)
?? ??? ??? ?;
?? ??? ?pre = q;?
?? ?}
?? ?return pre;
}
//在中序線索樹中找后繼結點?
BiTNode* InNext(BiTNode *p){
?? ?if(p->Rtag == 1){
?? ??? ?Next = p->RChild;
?? ?else{
?? ??? ?for(q = p->RChild; q->Ltag == 0; q = q->LChild)
?? ??? ??? ?;?? ?
?? ??? ?Next = q;
?? ?}
?? ?return Next;
?? ?}
}
//找中序遍歷線索樹第一個節點
BiTNode *InFirst(BiTNode *p){
?? ?if(!p) return NULL;
?? ?while(p->Ltag == 0) p = p->LChild;
?? ?return p;
}
//遍歷中序線索二叉樹
void TInOrder(BiTNode Bt){
?? ?BITNode *p;
?? ?p = InFirst(Bt);
?? ?while(p){
?? ??? ?visit(p);
?? ??? ?p = InNext(p);
?? ?}
}?
遍歷確定二叉樹:只有先序+中序, 后序+中序可以
嘗試還原: 先序 ABCDEFGHI
?? ??? ? ?中序 BCAEDGHFI
?? ??? ? ?二叉樹參考:
?? ??? ? ??? ?A
?? ??? ?B------------D
?? ??? ? -C ? ??? ?E----------F
?? ??? ? ?? ??? ??? ??? ?-G------I
?? ??? ? ?? ??? ??? ??? ? ?-H
樹的存儲結構:?
//雙親表示法?
typedef struct TNode{
?? ?int data;
?? ?int parent;
}TNode;
typedef struct{
?? ?TNode tree[MAX];
?? ?int nodenum;
}ParentTree;
//孩子兄弟表示法 重點!!!?
typedef DataNode int
typedef struct ChildNode{//孩子鏈表結點定義?
?? ?int Child;
?? ?struct ChildNode *next;
}ChildNode;
typedef struct{//順序表結點定義?
?? ?DataNode data;
?? ?ChildNode *FirstChild;
}DataNode;
typedef struct{
?? ?DataNode nodes[MAX];
?? ?int root;
?? ?int num;
}ChildTree;
//孩子表示法?
tepedef struct CSNode{
?? ?int data;
?? ?struct CSNode *FirstChild;
?? ?struct CSNode *NextChild;
}CSNode, *CSTree;?
森林,樹,二叉樹:
任意樹轉化為二叉樹:兄弟加平行線,刪右側加線端點的與雙親的連線,旋轉?
森林轉化二叉樹:第一顆二叉樹不懂,后面的二叉樹的根依次作為二前一棵二叉樹的右孩子?
注意:樹的先根遍歷-->轉換后二叉樹的先序遍歷
?? ? 樹的后根遍歷-->轉換后二叉樹的中序遍歷?
?
樹的遍歷算法://孩子兄弟鏈表實現對樹的先根遍歷?
void RootFirst(CSTree root){
?? ?if(root != NULL){
?? ??? ?Visit(root->data);
?? ??? ?p = root->FirstChild;
?? ??? ?while(p != NULL)
?? ??? ?{
?? ??? ??? ?RpptFirst(p);
?? ??? ??? ?p = p->NextSbling;
?? ??? ?}
?? ?}
}?
void RootFirst(CST root){
?? ?if(root != NULL){
?? ??? ?Visit(root->data);
?? ??? ?RootFirst(root->FirstChild);
?? ??? ?RootFirst(root->NextSibling);
?? ?}
}
哈夫曼樹:帶權葉子節點構成路徑長度最短的二叉樹,稱最優二叉樹?
路徑,路徑長度,結點的權,帶權路徑長度
類型定義:
#define N 20
#define M 2 * N -1
typedef struct{
?? ?int weight;
?? ?int parent;
?? ?int LChild;
?? ?int RChild;
}HTNode, HuffmanTree[M+1];
//Create the Tree
void CrtHuffmanTree(HuffmanTree ht, int w[], int n){
?? ?//create ht[M+1], w[]存放n個權值
?? ?for(i = 1; i <= n; i++)
?? ??? ?ht[i] = {w[i], 0, 0, 0};
?? ?//Attention, start from 1, not 0 . So the length of ht is M + 1, not M.
?? ?for(i = n + 1; n <= M; i++)
?? ??? ?ht[i] = {0, 0, 0, 0};
?? ??? ?
?? ?for(i = n + 1; i <= M; i++){
?? ??? ?select(ht,i-1, &s1, &s2);
?? ??? ?//從ht[1]~ht[i-1]中選擇兩個parent = 0且weight最小的結點, 其序號賦值給s1, s2
?? ??? ?ht[i].weight = ht[s1].weight + ht[s2].weight;
?? ??? ?ht[s1].parent = i;
?? ??? ?ht[s2].parent = i;
?? ??? ?ht[i].LChild = s1;
?? ??? ?ht[i].RChild = s2;
?? ?}
}?
//對于第三個for 循環如下
for(i = n + 1; i <= M;i++ ){
?? ?s1 = s2 = 32767;
?? ?Inode = rnode = -1;
?? ?for(k = 0; k <= i -1 ;k++){
?? ??? ?if(ht[k].parent == -1){
?? ??? ??? ?if(ht[k].weight<= s1){
?? ??? ??? ??? ?s2 = s1; rnode = Inode;
?? ??? ??? ??? ?s1 = ht[k].weight; Inode = k;
?? ??? ??? ?}
?? ??? ??? ?else if(ht[k].weight <= s2){
?? ??? ??? ??? ?s2 = ht[k].weight; rnode = k;
?? ??? ??? ?}
?? ??? ?}
?? ?}
}
//哈夫曼編碼_不用管,下一個可以看看?
void encoding(HuffmanTree ht, HuffmanCode hc, int n){
?? ?//n 為葉子結點個數
?? ?int start = n - 1;
?? ?char *cd;
?? ?cd = (char *)malloc((n + 1) * sizeof(char)); //暫時存入字符編碼的字符數組?
?? ?cd[n] = '\0';
?? ?for(i = 1; i <= n; i++){
?? ??? ?start = n;
?? ??? ?c = i;
?? ??? ?p = ht[i].parent;
?? ??? ?while(p != -1){
?? ??? ??? ?start--;
?? ??? ??? ?if(ht[p].LChild == c)
?? ??? ??? ??? ?cd[start] = '0';
?? ??? ??? ?else
?? ??? ??? ??? ?cd[start] = '1';
?? ??? ??? ?c = p;
?? ??? ??? ?p = ht[p].parent;//倒著存入的思想?
?? ??? ?}
?? ??? ?hc[i] = (char *)malloc((n+1-start) * sizeof(char));
?? ??? ?strcpy(hc[i], &cd[start]);
?? ??? ?cd = {'\0'};
?? ?}
?? ?free(cd);?
}?
#define LEN 100
typedef struct{
?? ?char ch;?? ??? ?//存儲字符?
?? ?char code[LEN]; //存放編碼?
}TCode;//每個字符都對應唯一編碼,因為哈夫曼樹為前綴編碼?
TCode CodeBook[LEN];//編碼本?
//哈夫曼編碼算法_2?
void encoding1(HTNode ht[], TCode book[], int n){
?? ?char *str = (char *)malloc((n + 1) * sizeof(char));//存放編碼?
?? ?str[n] = '\0';
?? ?int i, j, idx, p;
?? ?//哈夫曼樹某個葉結點下標idxa,用parent找到父節點idxb?
?? ?for(i = 0; i < n; i++){//依次求葉子結點ht[i]的編碼?
?? ??? ?book[i].ch = ht[i].ch;
?? ??? ?idx = i;
?? ??? ?j = n;
?? ??? ?while(p = ht[idx].parent > 0){
?? ??? ??? ?if(ht[p].LChild == idx){
?? ??? ??? ??? ?j--;
?? ??? ??? ??? ?str[j] = '0';//左孩子?
?? ??? ??? ?}
?? ??? ??? ?else{
?? ??? ??? ??? ?j--;
?? ??? ??? ??? ?str[j] = '1';//右孩子?
?? ??? ??? ?}
?? ??? ??? ?idx = p;// idx 為下一輪找雙親的孩子,因為p = ht[idx].parent;?
?? ??? ?}
?? ??? ?strcpy(book[i].code, &str[j]);
?? ?}
}
//解碼運算算法?
void decoding(HTNode ht[], char *codes, int n){
?? ?int p = 2 * n -2;//p為表中最后一個結點的指針, (總共2n-1個結點, 0開始), ht[p]代表root
?? ?int i, j;
?? ?i = 0;
?? ?while(codes[i]!= '\0'){
?? ??? ?while(ht[p].LChild !=-1 && ht[p].RChild != -1){
?? ??? ??? ?if(codes[i] == '0')
?? ??? ??? ??? ?p = ht[p].LChild;
?? ??? ??? ?else
?? ??? ??? ??? ?p = ht[p].LChild;
?? ??? ??? ?i++;
?? ??? ?}
?? ??? ?printf("%c", ht[p].ch);
?? ??? ?p = 2 * n -2;
?? ?}?
}
第六章總結:
存儲結構:
二叉樹采用順序儲存與二叉鏈表儲存
哈夫曼樹概念,了解相關實現.?
遍歷必考!
//icoding例題?
假設二叉樹采用二叉鏈表方式存儲, root指向根結點,node 指向二叉樹中的一個結點,
編寫函數 path,計算root到 node 之間的路徑,(該路徑包括root結點和 node 結點)。path 函數聲明如下:
bool path(BiTNode* root, BiTNode* node, Stack* s);
其中,root指向二叉樹的根結點,node指向二叉樹中的另一結點,s 為已經初始化好的棧,
該棧用來保存函數所計算的路徑,如正確找出路徑,則函數返回 true,此時root在棧底,node在棧頂;
如未找到,則函數返回 false, 二叉樹的相關定義如下:
typedef int DataType;
typedef struct Node{
? ? DataType data;
? ? struct Node* left;
? ? struct Node* right;
}BiTNode, *BiTree;
棧的相關定義及操作如下:
#define Stack_Size 50
typedef BiTNode* ElemType;
typedef struct{
? ? ElemType elem[Stack_Size];
? ? int top;
}Stack;
void init_stack(Stack *S); // 初始化棧
bool push(Stack* S, ElemType x); //x 入棧
bool pop(Stack* S, ElemType *px); //出棧,元素保存到px所指的單元,函數返回true,棧為空時返回 false
bool top(Stack* S, ElemType *px); //獲取棧頂元素,將其保存到px所指的單元,函數返回true,棧滿時返回 false
bool is_empty(Stack* S); ?// 棧為空時返回 true,否則返回 false
#include "bitree.h" //請不要刪除,否則檢查不通過
#include
#include
bool path(BiTNode* root, BiTNode* node, Stack* s)
{
? ? BiTNode *p, *q;?
? ? int i = 0;
? ? p = root;
? ? q = NULL;
? ? init_stack(s);
? ? if (p == NULL || node == NULL)
? ? ? ? return false;
? ? if (p == node) {
? ? ? ? push(s, p);
? ? ? ? return true;
? ? }
? ? while (p != NULL || !is_empty(s)) {
? ? ? ? while (p) {
? ? ? ? ? ? push(s, p);
? ? ? ? ? ? if (p == node)
? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? p = p->left;
? ? ? ? }
? ? ? ? top(s, &p);?
? ? ? ? if (p->right == q || p->right == NULL) {
? ? ? ? ? ? q = p;
? ? ? ? ? ? pop(s, &p);
? ? ? ? ? ? p = NULL;?
? ? ? ? } else {
? ? ? ? ? ? p = p->right;
? ? ? ? }
? ? }
? ? return false;
}
第七章 圖
概念:vertex, head, arc, tail, edge.子圖,鄰接點,鄰接邊,度,入/出度,網,路徑長度,回路,連通圖....?
分類:稀疏圖,完全圖,稠密圖
圖的存儲結構://重點
//鄰接表?
//分為表頭結點表和邊表
//前者是一個指針類型的結構數組 每一個結構包括結點域和鏈域
//邊表儲存弧結點, 弧結點結構分為三個域, 第一個儲存弧結點相關信息,?
//第二個一般可以儲存權重, 第三個鏈域存表頭結點的下一個鄰結點的弧?
#define MAX_VERTEX_NUM 20
typedef enum{DG, DN, UDG, UDN
} GraphKind;
typedef char VertexData
typedef struct ArcNode{//弧結點?
?? ?int adj;
?? ?int info;?
?? ?struct ArcNode *nextarc;//指向下一條弧的指針?
}ArcNode;
typedef struct VertexNode{//表頭結點?
?? ?VertexData data;
?? ?ArcNode *firstarc;
}VertexNode;
typedef struct{
?? ?VertexNode vertex[MAX_VERTEX_NUM];
?? ?int vexnum, arcnumber;
?? ?GraphKind kind;
}AdjList;
//鄰接矩陣
#define MAX_VERTEX_NUM 20
#define IFINITY
typedef enum{DG, DN, UDG, UDN
} GraphKind;
typedef char VertexData
typedef struct ArcNode{
?? ?int adj;
}ArcNode;
typedef struct{
?? ?VertexData vertex[MAX_VERTEX_NUM];
?? ?ArcNode arc[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
?? ?int vexnum, arcnumber;
?? ?GraphKind kind;
}AdjMatrix;
//求頂點位置函數?
int LocateVertex(AdjMatrix *G, VertexData v){
?? ?int i = 0;
?? ?for(; i < G->vexnum; i++){
?? ??? ?if(G->vertex[i] == v)
?? ??? ??? ?return i;?
?? ?}
?? ?return -1;
}
//創建一個有向網?
int CreateDN(AdjMatrix *G){
?? ?
?? ?int vexnum, arcnum;
?? ?VertexData v1, v2;
?? ?int i, j, k, weight;
?? ?
?? ?scanf("%d, %d", &vexnum, &arcnum);
?? ?for(i = 0; i< G->vexnum; i++)
?? ??? ?scanf("%c", &G->vertex[i]);
?? ?for(i = 0; i < G->vexnum; i++)
?? ??? ?for(j = 0; j < G->vexnum; j++)
?? ??? ??? ?G->arc[i][j] = IFINITY;
?? ?for(k = 0; k < G->arcnumber; k++){
?? ??? ?scanf("%c, %c, %d", &v1, &v2, &weight);
?? ??? ?i = LocateVertex(G, v1);
?? ??? ?j = LocateVertex(G, v2);
?? ??? ?G->arc[i][j] = weight;
?? ?}
?? ?return OK;
}
//十字鏈表?
#define MAX_VERTEX_NUM 20
typedef enum{DG, DN, UDG, UDN
} GraphKind;
typedef char VertexData
typedef struct ArcNode{
?? ?int tailvex; ? //儲存當前結點信息?
?? ?int headvex;?? ?//儲存下一個結點信息?
?? ?struct ArcNode *hlink;//入度?
?? ?struct ArcNode *tlink;//出度, 相當于鄰接表?
?? ?int info; ?? ??? ?//可以存權?
}ArcNode;
typedef struct VertexNode{
?? ?VertexData data;?? ?//頂點信息?
?? ?ArcNode *firstin;?? ?//入度的第一條弧//以該頂點為弧頭的第一個弧頂點?
?? ?ArcNode *firstout; ?//以該頂點為弧尾的第一個弧頂點?
}VertexNode;
typedef struct{
?? ?VertexNode vertex[MAX_VERTEX_NUM];
?? ?int vexnum, arcnum;
?? ?GraphKind kind;
}OrthList;
//創建十字鏈表算法?
void CrtOrthList(OrthList *g){
?? ?
?? ?int vexnum, arcnum;
?? ?int i, j, k;
?? ?VertexData vh, vt;
?? ?ArcNode *p;
?? ?
?? ?scanf("%d, %d", &vexnum, &arcnum);
?? ?g->vexnum = vexnum; g->arcnum = arcnum;
?? ?
?? ?for(i = 0; i < vexnum; i++){
?? ??? ?scanf("%c", &(g->vertex[i].data));
?? ??? ?g->vertex[i].firstin = NULL;
?? ??? ?g->vertex[i].firstout = NULL;?
?? ?}
?? ?
?? ?for(k = 0; k < arcnum; k++){
?? ??? ?scanf("%c, %c", &vh, &vt);
?? ??? ?i = LocateVertex(g, vt);
?? ??? ?j = LocateVertex(g, vh);
?? ??? ?p = (ArcNode *)malloc(sizeof(ArcNode));
?? ??? ?p->tailvex = i;
?? ??? ?p->headvex = j;
?? ??? ?//類似于頭插?
?? ??? ?p->tlink = g->vertex[i].firstout;
?? ??? ?g->vertex[i].firstout = p;
?? ??? ?p->hlink = g->vertex[j].firstin;
?? ??? ?g->vertex[j].firstin = p;
?? ?}
}
//鄰接多重表?
//鄰接多重表與鄰接表不同, 前者主要記錄邊的信息
//該表有標志域, 記錄是否被搜索過, 兩個頂點, 分別與兩個頂點關聯的邊?
#define MAX_VERTEX_NUM 20
typedef enum{DG, DN, UDG, UDN
} GraphKind;
typedef char VertexData
typedef struct EdgeNode{
?? ?int mark;
?? ?int ivex, jvex;
?? ?struct EdgeNode *ilink;
?? ?struct EdgeNode *jlink;//用于指向下一條依附于頂點jvex的邊 //頂點的鄰接邊?
}EdgeNode;
typedef struct{
?? ?VertexData data;
?? ?EdgeNode *firstedge;?
}VertexNode;
typedef struct{
?? ?VertexNode vertex[MAX_VERTEX_NODE];
?? ?int arcnum, vexnum;
?? ?GraphKind kind;
}AdjMulList;
總結:?
//鄰接矩陣:二維數組, 一維數組組成, 鄰接矩陣存是否兩個頂點之間有邊?
//鄰接表:頂點指針結構數組, 弧結點構成以頂點為頭結點的鏈表 , 節省稀疏圖對鄰接矩陣造成的的空間浪費?
//鄰接多重表:標志域, 兩個結點域, 兩個鏈域分別對應域兩個頂點的鄰接邊信息?
//十字鏈表: 鄰接表和逆鄰接表的結合, 每一個結點有兩個鏈域存出度和入度信息, 兩個數據域存結點信息?
?
總結
以上是生活随笔為你收集整理的第二个一千行总结-数据结构C复习--知识点总结2--五到七章的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 小腿肌肉怎样瘦
- 下一篇: 猪肉怎么做才好吃 猪肉的四种做法介绍