java插入算法

1. 遍歷算法(遍歷二叉樹6種方法)

1.1. 概述

遍歷算法針對二叉樹而言的,主要有先序、中序、後序三種遍歷順序,三種順序又分別有遞歸和常規算法,二叉樹遍歷的主要思想是:遍歷左子樹,遍歷右子樹,訪問根節點,由這三者的遍歷順序來確定是先序、中序還是後序。下面只要求掌握遞歸遍歷算法,常規遍歷算法見附錄一。

1.2. 先序遍歷算法

遍歷順序:訪問根節點,遍歷左子樹,遍歷右子樹。代碼如下:

void preOrder(BinaryTreeNode bt) {

if (bt == null)// 如果當前樹爲空,則終止遞歸

return;

System.out.print(bt.getData());// 先訪問根節點

preOrder(bt.getLeftChild());// 再遍歷左子樹

preOrder(bt.getRightChild());// 再遍歷右子樹

}

1.3. 中序遍歷算法

遍歷順序:遍歷左子樹,訪問根節點,遍歷右子樹。代碼如下:

void midOrder(BinaryTreeNode bt) {

if (bt == null)// 如果當前樹爲空,則終止遞歸

return;

preOrder(bt.getLeftChild());// 先遍歷左子樹

System.out.print(bt.getData());// 再訪問根節點

preOrder(bt.getRightChild());// 再遍歷右子樹

}

1.4. 後序遍歷算法

遍歷順序:遍歷左子樹,遍歷右子樹,訪問根節點。代碼如下:

void postOrder(BinaryTreeNode bt) {

if (bt == null)// 如果當前樹爲空,則終止遞歸

return;

preOrder(bt.getLeftChild());// 先遍歷左子樹

preOrder(bt.getRightChild());// 再遍歷右子樹

System.out.print(bt.getData());// 再訪問根節點

}

1.5. 層次遍歷算法

 

void levelOrder(BinaryTreeNode bt) {

if (bt == null)

return;

Queue q = new ArrayQueue();

q.enqueue(bt);

while (!q.isEmpty()) {

bt = (BinaryTreeNode) q.dequeue();// 取出隊首元素,訪問之

System.out.println(bt.getData());

if (bt.hasLeftChild()) {

q.enqueue(bt.getLeftChild());// 如果左節點存在,放入隊列中

}

if (bt.hasRightChild()) {

q.enqueue(bt.getRightChild());// 如果右節點存在,放入隊列中

}

}

}

2. 排序算法(9種排序算法)

2.1. 概述

將一個數據元素的任意序列,重新排列成一個按關鍵字有序的序列。

2.2. 插入類排序

基本思想是:逐個考察每個待排序元素,將每一個新元素插入到前面已經排好序的序列中適當的位置上,使得新序列仍然是一個有序序列。主要介紹三種:直接插入排序、折半插入排序和希爾排序。

2.2.1. 直接插入排序

思路:僅有一個元素的序列總是有序的,因此,對 個記錄的序列,可從第二個元素開始直到第 個元素,逐個向有序序列中執行插入操作,從而得到 個元素按關鍵字有序的序列。代碼如下:

void insert(int[] a) {

for (int i = 1; i < a.length; i++) {// 從第二個開始比較插入

// 待插入的元素比之前排好序的元素最大值小才需要插入

if (a[i] < a[i - 1]) {

int tmp = a[i];// 把當前位置騰出來

a[i] = a[i - 1];// 和已排好序的最大值交換順序

int j = i - 2;// 遍歷之前i-2個元素找出要插入的位置

// 如果待插入元素小於已排好序中的第j位並j不小於0則繼續遍歷

for (; j >= 0 && tmp < a[j]; j--)

a[j + 1] = a[j];

a[j + 1] = tmp;// j + 1即爲待插入位置

}

}

}

2.2.2. 折半插入排序

思路:可以不斷二分有序序列來確定插入位置,即搜索插入位置的方法可以使用折半查找實現。代碼如下:

void binaryInsert(int[] a) {

for (int i = 1; i < a.length; i++) {// 從第二個開始比較插入

// 待插入的元素比之前排好序的元素最大值小才需要插入

if (a[i] < a[i - 1]) {

int tmp = a[i];// 把當前位置騰出來

a[i] = a[i - 1];// 和已排好序的最大值交換順序

int low = 0, high = i - 1, mid;//high=好序列的長度

while (low < high) {

mid = (low + high) / 2;

if (tmp < a[mid])

high = mid - 1;

else

low = mid + 1;

}

int j = i - 2;// 遍歷之前i-2個元素找出要插入的位置

// high是因爲經過while循環後high一定是不大於low

for (; j > high; j--)

a[j + 1] = a[j];

a[high + 1] = tmp;// high + 1即爲待插入位置

}

}

}

2.2.3. 希爾排序

思路:首先將待排序的元素分爲多個子序列,使得每個子序列的元素個數相對較少,對各個子序列分 別進行直接插入排序,待整個待排序序列基本有序後,再對所有元素進行一次直接插入排序。

static void shell(int[] a) {

int d = 1;// 定義步長值

while (d <= a.length / 3)

d = d * 3 + 1;// 根據數組長度生成步長終值

for (; d > 0; d = (d - 1) / 3) {// 還原步長值

for (int i = d; i < a.length; i++) {// 從第1個步長開始比較插入

// 待插入的元素比之前排好序的元素最大值小才需要插入

if (a[i] < a[i - d]) {

int tmp = a[i];// 把當前位置騰出來

a[i] = a[i - d];// 和已排好序的最大值交換順序

int j = i - d - 1;// 遍歷之前i-d-1個元素找出要插入的位置

// 如果待插入元素小於已排好序中的第j位並j不小於0則繼續遍歷

for (; j >= 0 && tmp < a[j]; j -= d)

a[j + d] = a[j];

a[j + d] = tmp;// j + d即爲待插入位置

}

}

}

}

2.3. 交換類排序

2.3.1. 基本思想

交換類排序主要是通過兩兩比較待排元素的關鍵字,若發現與排序要求相逆,則交換之。

2.3.2. 冒泡排序

void bubble(int[] a) {

for (int i = 0; i < a.length; i++) {// 先遍歷數組

for (int j = 1; j < a.length - i; j++) {// 遍歷未排好序的len-i個元素

if (a[j - 1] > a[j]) {// 前後比較

int tmp = a[j - 1];

a[j - 1] = a[j];

a[j] = tmp;

}

}

}

}

2.3.3. 快速排序

思路:劃分步驟:通過樞軸元素 x 將序列一分爲二, 且左子序列的元素均小於 x,右子序列的元素均大於 x;治理步驟:遞歸的對左、右子序列排序;

void quick(int[] a, int low, int high) {

if (low < high) {

int part = partition(a, low, high);

quick(a, low, part - 1);

quick(a, part + 1, high);

}

}

int partition(int[] a, int low, int high) {

int tar = a[low];

while (low < high) {// 循環該段數據

while (low < high && tar < a[high])// 先從高端開始查找

high--;

a[low] = a[high];// 交換數據

while (low < high && tar > a[low])// 再從低端開始查找

low++;

a[high] = a[low];// 交換數據

}

a[low] = tar;// 重新設置樞軸

return low;// 返回樞軸位置

}

2.4. 選擇類排序

2.4.1. 概述

每一趟從 n-i+1 (i=1,2,…,n)個元素中選取一個關鍵字最小的元素作爲有序序列中第 個元素。

2.4.2. 簡單選擇排序

void recursionSort(int[] arr, int index) {// 遞歸選擇排序

if (index < arr.length) {

for (int i = 0; i < arr.length; i++) {

if (arr[index] < arr[i]) {

int tmp = arr[index];

arr[index] = arr[i];

arr[i] = tmp;

}

}

index++;

recursionSort(arr, index);

}

}

void commonSort(int[] arr) {// 簡單選擇排序

for (int i = 0; i < arr.length; i++) {

for (int j = i + 1; j < arr.length; j++) {

if (arr[i] > arr[j]) {

int tmp = arr[j];

arr[j] = arr[i];

arr[i] = tmp;

}

}

}

}

2.4.3. 樹形選擇排序和堆排序(附錄二)

2.5. 並歸排序排序

思想:

1. 劃分:將待排序的序列劃分爲大小相等(或大致相等)的兩個子序列;

2. 治理:當子序列的規模大於 時,遞歸排序子序列,如果子序列規模爲 則成爲有序序列;

3. 組合:將兩個有序的子序列合併爲一個有序序列。

void msort(int[] a, int low, int high) {

if (low < high) {

msort(a, low, (high + low) / 2);

msort(a, (high + low) / 2 + 1, high);//並歸後半段

merge(a, low, (high + low) / 2, high);//並歸前半段

}

}

void merge(int[] a, int p, int q, int r) {

int[] b = new int[r - p + 1];

int s = p;//並歸apqq+1r兩個數組

int t = q + 1;

int k = 0;

while (s <= q && t <= r)//並歸交叉段

if (a[s] < a[t])

b[k++] = a[s++];

else

b[k++] = a[t++];

while (s <= q)//並歸剩下的段

b[k++] = a[s++];

while (t <= r)

b[k++] = a[t++];

for (int i = 0; i < b.length; i++)

a[p + i] = b[i];

}

2.6. 各種排序之間的比較

 

 

3. 查找算法(3種查找算法)

3.1. 順序查找

int order(int[] array, int tar) {

for (int i = 0; i < array.length; i++) {

if (tar == array[i])

return i + 1;

}

return -1;

}

3.2. 折半查找

// 二分法查找遞歸

int binRecursion(int[] array, int tar, int low, int high) {

int mid;

if (low > high)

return -1;

mid = (high + low) / 2;

if (tar == array[mid])

return mid;

else if (tar > array[mid])

binRecursion(array, tar, mid++, high);

else

binRecursion(array, tar, low, mid--);

return -1;

}

// 二分法查找非遞歸

int bin(int[] array, int tar) {

int low = 0, high = array.length - 1, mid;

while (low <= high) {

mid = (low + high) / 2;

if (array[mid] == tar)

return mid;

else if (array[mid] < tar)

low = mid + 1;

else

high = mid - 1;

}

return -1;

}

3.3. 二叉樹查找

BinaryTreeNode binaryTreeRecusion(BinaryTreeNode bt, Object tar) {// 二叉樹遞歸查找算法

if (bt == null)

return new BinaryTreeNode("null");

switch (strategy.compare(tar, bt.getData())) {

case -1:// tardata小就查找左子樹

return binaryTreeRecusion(bt.getLeftChild(), tar);

case 1:// tardata大就查找右子樹

return binaryTreeRecusion(bt.getRightChild(), tar);

default:// 比較結果是0tardata相等就返回

return bt;

}

}

BinaryTreeNode binaryTree(BinaryTreeNode bt, Object tar) {// 二叉樹非遞歸查找算法

while (bt != null) {

switch (strategy.compare(tar, bt.getData())) {

case -1:// tardata小就查找左子樹

return bt = bt.getLeftChild();

case 1:// tardata大就查找右子樹

return bt = bt.getRightChild();

default:// 比較結果是0tardata相等就返回

return bt;

}

}

return new BinaryTreeNode("null");

}

4. 附錄一

void preOrder(BinaryTreeNode p) {// 二叉樹先序遍歷非遞歸算法

Stack s = new SingleLinkedStack();

while (p != null) {

while (p != null) {

System.out.println(p.getData());// 訪問根節點

if (p.hasRightChild()) {// 右子樹壓棧

s.push(p.getRightChild());

}

p = p.getLeftChild();// 繼續訪問左子樹直到爲空

}

if (!s.isEmpty()) {

p = (BinaryTreeNode) s.pop();// 噹噹前左子樹遍歷完成,存右子樹的棧退棧

}

}

}

 

// 找到最左節點

BinaryTreeNode goFarLeft(BinaryTreeNode bt, Stack s) {

if (bt == null)

return null;

while (bt.hasLeftChild()) {

s.push(bt);

bt = bt.getLeftChild();

}

return bt;

}

void midOrder(BinaryTreeNode bt) {// 二叉樹中序遍歷的非遞歸算法

Stack s = new SingleLinkedStack();

BinaryTreeNode p = goFarLeft(bt, s);// 找到最左節點

// 如果最左節點不爲空則繼續查找

while (p != null) {

System.out.println(p.getData());// 訪問根節點

if (p.hasRightChild()) {

// 如果有右孩子節點,則訪問有孩子節點的最左孩子節點

p = goFarLeft(p.getRightChild(), s);

else if (!s.isEmpty()) {

// 如果沒有右孩子節點且棧不爲空,則彈棧往回找上一級

p = (BinaryTreeNode) s.pop();

else

p = null;// 棧爲空則查找完成

}

}

void lastOrder(BinaryTreeNode p) {// 二叉樹後序遍歷非遞歸算法

Stack s = new SingleLinkedStack();

BinaryTreeNode pre = null;// 緩存上次訪問節點

// 如果最左節點不爲空則繼續查找

while (p != null || !s.isEmpty()) {

while (p != null) {// 查找最左節點

s.push(p);

p = p.getLeftChild();

}

if (!s.isEmpty()) {

// 取出棧頂節點

p = (BinaryTreeNode) s.peek();

// 判斷當前節點是否是父親節點的右子節點,如果是

// 只需訪問其父節點即可完成以p的父節點爲根節點的子樹的訪問

if (!p.hasRightChild() || p.getRightChild() == pre) {

list.insertLast(p);

s.pop();

pre = p;

p = null;

else

p = p.getRightChild();

}

}

}

5. 附錄二

堆排序:

// 已知 r[low..high]中除 r[low]之外,其餘元素均滿足堆的定義

private void heapAdjust(int[] r, int low, int high) {

int tmp = r[low];

for (int j = 2 * low; j <= high; j = j * 2) { // 沿關鍵之較大的元素向下進行篩選

if (j < high && r[j] > r[j + 1])// j 指向關鍵之較大的元素

j++;

if (tmp >= r[j])// 若 temp 比其孩子都大,則插入到 low 所指位置

break;

r[low] = r[j];

low = j; // 向下篩選

}

r[low] = tmp;

}

public void heapSort(int[] r) {

int n = r.length - 1;

for (int i = n / 2; i >= 1; i--)

// 初始化建堆

heapAdjust(r, i, n);

for (int i = n; i > 1; i--) { // 不斷輸出堆頂元素並調整 r[1..i-1]爲新堆

int tmp = r[1]; // 交換堆頂與堆底元素

r[1] = r[i];

r[i] = tmp;

heapAdjust(r, 1, i - 1); // 調整

}

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章