1.順序棧
結構:(top總是指向數組最後的元素,比如data[n],而不是前面)
#define MAXSIZE 100
typedef struct
{
elementtype data[MAXSIZE];
int top;
} seqstack;
初始化棧:
void init_stack(seqstack *S)
{
S->top = -1; //一個元素也沒有,注意因爲TOP是下標而不是元素個數,用-1
}
判斷棧是否爲空:
int stack_empty(seqstack *S)
{
if (S->top == -1)
return 1;
else
return 0;
}
取棧頂元素:
elementtype stack_top(seqstack *S)
{
if (stack_empty(S))
error("棧爲空!");
else
return S->data[S->top];
}
入棧:
void push_stack(seqstack *S, elementtype x)
{
if (S->top == MAXSIZE -1)
error("溢出!");
else
S->data[++S->top] = x; //注意->運算符的優先級是最高的
}
出棧:
elementtype pop_stack(seqstack *S)
{
if (stack_empty(S))
error("棧爲空!");
else
return S->data[S->top--];
}
判斷棧是否爲滿:
int stack_full(seqstack *S)
{
if (S->top == MAXSIZE -1)
return 1;
else
return 0;
}
棧的鏈式存儲結構稱爲鏈棧。
其插入和刪除操作僅限制在表頭位置上進行。
由於只能在鏈表頭部進行操作,故鏈棧沒有必要象單鏈表那樣添加頭結點。棧頂指針就是鏈表的頭指針。
typedef struct node //和一般鏈表的結構一樣。
{
elementtype data;
struct node *next;
} linkstack;
linkstack *top;
當top=NULL時,鏈棧爲空棧。
入棧:
void push_stack(linkstack *top, elementtype x)
{
linkstack *P = (linkstack *)malloc(sizeof(linkstack));
P->data = x;
P->next = top->next;
top = P;
}
出棧:
elementype pop_stack(linkstack *top)
{
elementtype x;
linkstack *P;
if (top == NULL)
error("棧爲空!");
else
{
x = top->data;
P = top;
top = top->next;
free(P);
return x;
}
}
注意順序隊列多是循環隊列,這裏要注意幾點:
(1)front是隊頭的前一個位置。
(2)尾部入隊,頭部出隊。
(3)由於循環,任何的位置移動計算之後要取餘:P = (P + 1) % MAXSIZE 。
#define MAXSIZE 100
typedef struct
{
elementtype data[MAXSIZE];
int front; //頭序號(注意是隊頭的前一個位置)
int rear; //尾序號(直接指向尾元素)
} seqqueue;
初始化隊列:
void init_queue(seqqueue *Q)
{
Q->front = 0;
Q->rear = 0;
}
還有一種寫法:
void init_queue(seqqueue *Q)
{
Q->front = MAXSIZE - 1;
Q->rear = MAXSIZE - 1;
}
兩種方法的區別是第一種插入第一個元素是data[1],而第二種是data[0]。
判斷隊列是否爲空:
int queue_empty(seqqueue *Q)
{
if (Q->front == Q->rear)
return 1;
else
return -1;
}
判斷隊列是否爲滿:
int queue_full(seqqueue *Q)
{
if ((Q->rear + 1) % MAXSIZE == Q->front)
return 1;
else
return 0;
}
取隊頭元素:
elementtype queue_front(seqqueue *Q)
{
if (queue_empty(Q))
error("隊列爲空!");
else
return Q->data[(Q->front + 1) % MAXSIZE];
}
入隊:
void Enqueue(seqqueue *Q, elementtype x)
{
if (queue_full(Q))
error("隊列滿!");
else
{
Q->rear = (Q->rear + 1) % MAXSIZE; //千萬不能直接用Q->rear++,在循環隊列要特別注意
Q->data[Q->rear] = x;
}
}
出隊:
elementtype Outqueue(seqqueue *Q)
{
if (queue_empty(Q))
error("隊列爲空!");
else
{
Q->front = (Q->front + 1) % MAXSIZE;
return Q->data[Q->front];
}
}
typedef struct mynode
{
elementtype data;
mynode *next;
} node; //就是單鏈表
typedef struct
{
node *front;
node *rear;
} linkqueue;
初始化隊列:
void init_queue(linkqueue *Q)
{
Q->front = (node *)malloc(sizeof(node)); //生成頭結點(注意是NODE類型,Q結構是已有的一個結構,這裏有點特殊,仔細體會)
Q->rear = Q->front;
Q->front = NULL;
}
判斷隊列是否爲空:
int queue_empty(linkqueue *Q)
{
if (Q->front == Q->rear)
return 1;
else
return 0;
}
取隊頭元素:
elementtype queue_front(linkqueue *Q)
{
if (queue_empty(Q))
error("隊列爲空!");
else
return Q->front->next->data;
}
入隊:
void Enqueue(linkqueue *Q, elementtype x)
{
node *P = (node *)malloc(sizeof(node));
P->data = x;
P->next = NULL;
Q->rear->next = P;
Q->rear = P;
}
出隊:
elementtype Outqueue(linkqueue *Q)
{
node *P;
elmenttype x;
if (queue_empty(Q))
error("隊列爲空!");
else
{
P = Q->front->next;
Q->front->next = P->next;
x = P->data;
free(P);
}
if (Q->front->next == NULL) //只剩一個結點刪除後隊列爲空時的特殊情況,一定要注意處理
Q->rear = Q->front;
return x;
}
結構如下:
#define MAXSIZE 100
typedef struct //三元組結構
{
int i, j;
elementtype v;
} tuple;
typedef struct
{
int mu, nu, tu; //行數、列數、非0元素個數
tuple data[MAXSIZE];
} spmatrix;
二叉樹的性質:
4.有n個結點的完全二叉樹(n>0)的深度爲[log2n]+1([]爲取整)
void preorder(bitree *T)
{
if (T != NULL)
{
visit(T); //一般用的最多的就是輸出
preorder(T->lchild);
preorder(T->rchild);
}
}
typedef struct node
{
int ltag, rtag; //0爲孩子,1爲前驅或後繼
datatype data;
struct node *lchild, *rchild;
} ordertree;
先序後繼的求解:
ordertree *presuc(ordertree *P)
{
if (P->ltag == 0)
return P->lchild;
else
return P->rchild;
}
中序後繼:
ordertree *insuc(ordertree *P)
{
ordertree *q = P->rchild;
if (P->rtag == 1)
return q;
else
{
while (q->ltag == 0)
q = q->lchild;
return q;
}
}
中序先驅:
ordertree *infore(ordertree *P)
{
ordertree *q = P->lchild;
if (P->ltag == 1)
return q;
else
{
while (q->rtag == 0)
q = q->rchild;
return q;
}
}
後序先驅:
ordertree *postfore(ordertree *P)
{
if (P->rtag == 0)
return P->rchild;
else
return P->lchild;
}
typedef struct node //鏈表中每個孩子結點的定義
{
int data;
struct node *next;
} listnode;
typedef struct //數組元素的定義,每個數組元素都是一個單鏈表,單頭元素不同
{
datatype info;
listnode *firstchild;
} arrnode;
arrnode tree[MAXSIZE]; //MAXSIZE爲所有結點的個數
遍歷樹(森林)要轉換爲遍歷其對應的二叉樹:
先序遍歷:(同二叉樹的先序遍歷)
void preorder(tnode *T)
{
if (T != NULL)
{
visit(T);
preorder(T->firstchild);
preorder(T->nextbrother);
}
}
後序遍歷:(同二叉樹的中序遍歷)
void postorder(tnode *T)
{
if (T != NULL)
{
postorder(T->firstchild);
visit(T);
postorder(T->nextbrother);
}
}
其中弧表示單向關係,邊表示雙向關係,用離散數學中的術語來說,則分別表示爲非對稱關係和對稱關係。
#define n 6 /* 圖頂點數 */
#define e 8 /* 圖的邊(弧)數 */
typedef struct
{
vextype vexs[n]; /* 頂點類型 */
datatype arcs[n][n]; /* 權值類型 */
} graph;
建立一個無向網絡的算法:
CreateGraph(graph *G)
{
int i, j, k;
float w;
for (i=0; i<n; i++)
G->vexs[i] = getchar(); /* 讀入頂點信息,創建表,這裏用字符型 */
for (i=0; i<n; i++)
for (j=0; j<n; j++)
G->arcs[i][j] = 0; /* 鄰接矩陣初始化 */
for (k=0; k<e; k++)
{
scanf("%d%d%f", &i, &j, &w); /* 讀入邊(vi, vj)上的權w(暫用float類型) */
G->arcs[i][j] = w;
G->arcs[j][i] = w;
}
}
typedef struct node
{
int adjvex; /* 鄰接點域 */
struct node *next; /* 鏈域 */
datatype arc; /* 權值 */
} edgenode; /* 邊表指針 */
typedef struct
{
vextype vertex; /* 頂點信息 */
edgenode *link; /* 邊表頭指針 */
} vexnode; /* 頂點表結點 */
vexnode gnode[n]; /* 整個圖的構成 */
建立無向圖的鄰接表:
CreateAdjlist(gnode)
{
int i, j, k;
edgenode *s;
for (i=0; i<n; i++) /* 讀入頂點信息 */
{
gnode[i].vertex = getchar();
gnode[i].link = NULL; /* 邊表指針初始化 */
}
for (k=0; k<e; k++) /* 建立邊表 */
{
scanf("%d%d", &i, &j); /* 讀入邊(vi,vj)的頂點序號 */
s = malloc(sizeof(edgenode)); /* 生成鄰接點序號爲j的表結點 */
s->adjvex = j;
s->next = gnode[i].link;
gnode[i].link = s; /* 將*s插入頂點vi的邊表頭部(插到頭部比尾部簡單) */
s = malloc(sizeof(edgenode)); /* 生成鄰接點序號爲i的邊表結點*s */
s->adjvex = i;
s->next = gnode[j].link;
gnode[j].link = s; /* 將*s插入頂點vj的邊表頭部(最後四行由於是無向圖,所以相互,兩次) */
}
}
depth first search:
void dfs(graph G, int v)
{
int w;
visit(v);
visited[v] = 1;
w = firstadj(G, v)
while (w != 0)
{
if (visited[w] == 0)
dfs(w);
w = nextadj(G, v, w);
}
}
void dfs_travel(graph G)
{
int i;
for (i=1; i<=n; i++)
visited[i] = 0; //初始化各頂點的訪問標誌
for (i=1; i<=n; i++)
if (visited[i] == 0)
dfs(G, i);
}
void bfs(graph G, int V0)
{
int w;
int v;
queue Q;
init_queue(Q);
visit(V0);
visited[V0] = 1;
Enqueue(Q, V0);
while (!empty(Q))
{
v = Outqueue(Q);
w = firstadj(G, v);
while (w != 0)
{
if (visited[w] == 0)
{
visit(w);
visited[w] = 1;
Enqueue(Q, w);
}
w = nextadj(G, v, w);
}
}
}
廣度遍歷圖的算法和深度一樣:
void bfs_travel(graph G)
{
int i;
for (i=1; i<=n; i++)
visited[i] = 0;
for (i=1; i<=n; i++)
if (visited[i] = 0)
bfs(G, i);
}
在一個數據表中,若某字段的值可以標識一個數據元素,則稱之爲關鍵字(或鍵)。
int seq_seach(elementtype A[], int n, keytype x)
{
int i;
A[0].key = x; //設定監視哨
for (i=n; A[i].key!=x; i--);
return i;
}
int bin_search(elementtype A[], int n, keytype x)
{
int mid, low, high;
low = 0;
high = n - 1;
while (low <= high)
{
mid = (low + high) / 2;
if (x == A[mid].key)
return mid;
else if (x < A[mid].key)
high = mid - 1;
else
low = mid + 1;
}
return -1;
}
int bin_search(elementtype A[], int low, int high, keytype x)
{
int mid;
if (low < high)
return -1;
else
{
mid = (low + high) / 2;
if (x == A[mid].key)
return mid;
else if (x < A[mid],key)
return bin_search(A, low, mid - 1, x);
else
return bin_search(A, mid - 1, high, x);
}
}
void insert_sort(elementtype A[n+1])
{
int i;
for (i=2; i<=n; i++)
{
A[0] = A[i]; //設置監視哨,這個數組同樣是從1開始,A[0]就設爲監視哨
j = i - 1;
while (A[j].key > A[0].key)
{
A[j + 1] = A[j];
j--;
}
A[j + 1] = A[0];
}
}
int partition(elementtype A[n], int s, int t) //s,t是要排序元素的起點和終點,並返回最後中間元素位置
{
elementtype x = A[s]; //保存中間元素到臨時變量x,以騰出空位
int i = s; //置兩端搜索位置的初值
int j = t;
while (i != j) //兩端位置重和再停止
{
while (i < j && A[j].key > x.key) j--; //從後面搜索“小”的元素
if (i < j) //如果找到,就調到前面的空位中
{
A[i] = A[j];
i++;
}
while (i < j && A[i].key < x.key) i++; //從前面搜索“大”的元素
if (i < j) //如果找到,調到後面的空位中
{
A[j] = A[i];
j--;
}
}
A[i] = x; //將中間數移到最終位置上
return i;
}
void quick_sort(elementtype A[n], int s, int t) //對數組中下標從s到t的部分進行快速排序,如果是整個表就是0, n-1
{
int i;
if (s < t) //表中至少有兩個元素時
{
i = partition(A, s, t); //劃分排序一次
quick_sort(A, i + 1, t); //對後面部分快速排序
quick_sort(A, s, i - 1); //對前面部分快速排序
}
}
在待排序子表中完整地比較一遍以確定最大(小)元素,並將該元素放在子表的最前(後)面。
【注:可能發覺和冒泡法比較類似,但注意選擇法是全部比較一遍,找到最小元素的下標,再進行一次交換,而冒泡則是進行多次交換】
void select_sort(elementtype A[n])
{
int min, i, j;
elementtype temp;
for (i=0; i<n-1; i++)
{
min = i;
for (j=i+1; j<n; j++)
if (A[min].key > A[j].key) min = j;
if (min != i)
{
temp = A[i];
A[i] = A[min];
A[min] = temp;
}
}
}
void merge(elementtype A[], elementtype B[], elementtype C[], int m, int n)
{
int ia = 0, ib = 0, ic = 0;
while (ia < m && ib < n)
if (A[ia] <= B[ib])
C[ic++] = A[ia++];
else
C[ic++] = B[ib++];
while (ia < m)
C[ic++] = A[ia++];
while (ib < n)
C[ic++] = B[ib++];
}