算法思想:若 p 所指结点不为空,则访问该结点,然后将该结点的地址入栈,然后再将 p 指向其左孩 子结点;若 p 所指向的结点为空,则从堆栈中退出栈顶元素(某个结点的地址),将 p 指向其右孩子 结点。重复上述过程,直到 p = NULL 且堆栈为空,遍历结束。
#define MAX_STACK 50
voidPreOrderTraverse(BTree T){ BTree STACK[MAX_STACK], p = T; int top = -1; while(p!=NULL || top != -1){ while(P != NULL){ Visit(p); STACK[++top] = p; p = p->lchild; } p = STACK[top--]; p = p->rchild; } }
二叉树的中序遍历(非递归算法)
算法思想:若 p 所指结点不为空,则将该结点的地址 p 入栈,然后再将 p 指向其左孩子结点;若 p 所 指向的结点为空,则从堆栈中退出栈顶元素(某个结点的地址)送 p,并访问该结点,然后再将 p 指 向该结点的右孩子结点。重复上述过程,直到 p = NULL 且堆栈为空,遍历结束。
#define MAX_STACK 50
voidInOrderTraverse(BTree T){ BTree STACK[MAX_STACK], p = T; int top = -1; while (p != NULL || top != -1){ while (p != NULL){ STACK[++top] = p; p = p->lchild; } p = STACK[top--]; Visit(p); p = p->rchild; } }
二叉树的后序遍历(非递归算法)
算法思想:当 p 指向某一结点时,不能马上对它进行访问,而要先访问它的左子树,因而要将此结点 的地址入栈;当其左子树访问完毕后,再次搜索到该结点时(该结点地址通过退栈得到),还不能对 它进行访问,还需要先访问它的右子树,所以,再一次将该结点的地址入栈。只有当该结点的右子 树访问完毕后回到该结点时,才能访问该结点。为了标明某结点是否可以访问,引入一个标志变量 flag,当 flag = 0 时表示该结点暂不访问,flag = 1 时表示该结点可以访问。flag 的值随同该结点的地 址一起入栈和出栈。因此,算法中设置了两个堆栈,其中 STACK1 存放结点的地址,STACK2 存放 标志变量 flag,两个堆栈使用同一栈顶指针 top,且 top 的初始值为 −1。
#define MAX_STACK 50
voidPostOrderTraverse(BTree T){ BTree STACK1[MAX_STACK], p = T; int STACK2[MAX_STACK], flag, top = -1; while (p != NULL || top != -1) { while (p != NULL) { STACK1[++top] = p; STACK2[top] = 0; p = p->lchild; } p = STACK1[top]; flag = STACK2[top--]; if (flag == 0) { STACK1[++top] = p; STACK2[top] = 1; p = p->rchild; } else { VISIT(p); p = NULL; } } }
#define MAX_STACK 50 BTree DeleteSubtree(BTree &T, int item){ BTree STACK[MAX_STACK], q, p = T; int top = -1; if (T->data == item) { DestroyBT(T); T = NULL; returnNULL; } else { while (p != NULL || top != -1) { while (p != NULL) { if (p->data == item) { if (q->lchild == p) q->lchild = NULL; else q->rchild = NULL; DestroyBT(p); return T; } STACK[++top] = p; q = p; p = p->lchild; } q = STACK[top--]; p = q->rchild; } } }
图
查找
顺序查找的递归算法
intRecurSeqSearch(int A[], int n, int key, int i){ if (i >= n) return-1; if (A[i] == key) return i; else returnRecurSeqSearch(A, n, key, i + 1); } voidsolve(){ pos = RecurSeqSearch(A, n, key, 0); }
折半查找
intBinSearch(int A[], int n, int key){ int low = 0, high = n - 1, mid; while (low <= high) { mid = (low + high) / 2; if (key == A[mid]) return mid; if (key > A[mid]) low = mid + 1; else high = mid – 1; } return-1; }
折半查找的递归算法
intRecurBinSearch(int A[], int low, int high, int key){ int mid; if (low > high) return-1; else { mid = (low + high) / 2; if (key == A[mid]) return mid; if (key > A[mid]) returnRecurBinSearch(A, mid + 1, high, key); else returnRecurBinSearch(A, low, mid - 1, key); } } voidsolve(){ pos = RecurBinSearch(A, 0, n - 1, key); }
在按值递增排列且长度为 n 的线性表中折半查找并插入一元素
voidBinInsert(int A[], int &n, int key){ int j, low = 0, high = n - 1, mid; while (low <= high) { mid = (low + high) / 2; if (key > A[mid]) low = mid + 1; else high = mid – 1; } for (j = n; j > low; j--) A[j] = A[j - 1]; A[low] = key; n++; }
在按值递增排列且长度为 n 的线性表中折半查找值不小于 key 的最小元素
voidBinSearch(int A[], int n, int key){ int low = 0, high = n - 1, mid; while (low <= high) { mid = (low + high) / 2; if (key == A[mid]) return mid; if (key > A[mid]) low = mid + 1; else high = mid – 1; } if (low <= n - 1) return low; else return-1; }
排序
插入排序
算法思想:第 i 趟插入排序为:在含有 i − 1 个元素的有序子序列中插入一个元素,使之成为含有 i 个元素的有序子序列。在查找插入位置的过程中,可以同时后移元素。整个过程为进行 n − 1 趟插入, 即先将整个序列的第 1 个元素看成是有序的,然后从第 2 个元素起逐个进行插入,直到整个序列有序 为止。
voidInsertSort(int A[], int n){ int i, j, temp; for (i = 1; i <= n - 1; i++) { if (A[i] < A[i - 1]) { j = i - 1; temp = A[i]; while (j >= 0 && temp < A[j]) { A[j + 1] = A[j]; j--; } A[j + 1] = temp; } } }
折半插入排序
算法思想:算法同直接插入排序,只不过使用折半查找的方法来寻找插入位置。
voidBinInsertSort(int A[], int n){ int i, j, low, high, mid, temp; for (i = 1; i <= n - 1; i++) { temp = A[i]; low = 0; high = i – 1; while (low <= high) { mid = (low + high) / 2; if (temp > A[mid]) low = mid + 1; else high = mid – 1; } for (j = i; j > low; j--) A[j] = A[j - 1]; A[low] = temp; } }
冒泡排序
算法思想:首先将第 1 个元素和第 2 个元素进行比较,若前者大于后者,则两者交换位置,然后比较 第 2 个元素和第 3 个元素。依此类推,直到第 n − 1 个元素和第 n 个元素进行过比较或交换为止。上 述过程称为一趟冒泡排序,其结果是使得 n 个元素中值最大的那个元素被安排在最后一个元素的位置 上。然后进行第二趟排序,即对前 n − 1 个元素进行同样的操作,使得前 n − 1 个元素中值最大的那 个元素被安排在第 n − 1 个位置上。一般地,第 i 趟冒泡排序是从前 n − i + 1 个元素中的第 1 个元素 开始,两两比较,若前者大于后者,则交换,结果使得前 n − i + 1 个元素中最大的元素被安排在第 n − i + 1 个位置上。显然,判断冒泡排序结束的条件是“在一趟排序中没有进行过交换元素的操作”, 为此,设立一个标志变量 flag,flag = 1 表示有过交换元素的操作,flag = 0 表示没有过交换元素的操 作,在每一趟排序开始前,将 flag 置为 0,在排序过程中,只要有交换元素的操作,就及时将 flag 置 为 1。因为至少要执行一趟排序操作,故第一趟排序时,flag = 1。
voidBubbleSort(int A[], int n){ int i, j, temp, flag = 1; for (i = n - 1; i >= 1 && flag == 1; i--) { flag = 0; for (j = 0; j < i; j++) { if (A[j] > A[j + 1]) { temp = A[j]; A[j] = A[j + 1]; A[j + 1] = temp; flag = 1; } } } }
选择排序
算法思想:第 i 趟排序从序列的后 n − i + 1(i = 1, 2, …, n − 1)个元素中选择一个值最小的元素与该 个元素的第 1 个元素交换位置,即与整个序列的第 i 个元素交换。依此类推,直到 i = n − 1 为止。也 就是说,每一趟排序从从未排好序的那些元素中选择一个值最小的元素,然后将其与这些未排好序 的元素中的第 1 个元素交换位置。
voidSelectSort(int A[], int n){ int i, j, min, temp; for (i = 0; i < n; i++) { min = i; for (j = i + 1; j < n; j++) { if (A[min] > A[j]) min = j; } if (min != i) { temp = A[min]; A[min] = A[i]; A[i] = temp; } } }
voidQuickSort(int A[], int n){ QSort(A, 0, n - 1); } voidQSort(int A[], int low, int high){ int pivotloc; if (low < high) { pivot = Partition(A, low, high); QSort(A, low, pivotloc - 1); QSort(A, pivotloc + 1, high); } } intPartition(int A[], int low, int high){ int pivot; pivot = A[low]; // 从线性表的两端交替地向中间扫描 while (low < high) { while (low < high && A[high] >= pivot) high--; A[low] = A[high]; while (low < high && A[low] <= pivot) low++; A[high] = A[low]; } A[low] = pivot; return low; }
堆排序
voidHeapSort(int A[], int n){ int i, temp; // 建立大顶堆 for (i = n / 2; i >= 1; i--) HeapAdjust(A, i, n); for (i = n - 1; i >= 1; i--) { temp = A[1]; A[1] = A[i + 1]; A[i + 1] = temp; // 将 A[1..i] 重新调整为大顶堆 HeapAdjust(A, 1, i); } } voidHeapAdjust(int A[], int low, int high){ int i, temp; temp = A[low]; for (i = 2 * low; i <= high; i = i * 2) { // 令 i 为关键字较大的记录的下标 if (i < high && A[i] < A[i + 1]) i++; if (temp >= A[i]) break; else { A[low] = A[i]; low = i; } } A[low] = temp;// 插入 }