1. 程式人生 > >連結串列和樹

連結串列和樹

連結串列

   連結串列是一種遞迴的資料結構,它或者為空(null),或者是指向一個節點的引用,該節點含有一個泛型的元素和一個指向另一條連結串列的引用。

   在面向物件的程式設計中,實現連結串列並不困難。

public class MyNode<E> {

MyNode<E> next;

E item;

}

一個Node物件含有兩個例項變數,型別分別為Item和MyNode。

Item表示值,而如果first是一個指向某個MyNode物件的變數,我們可以使用first.item和first.next訪問它的例項變數。

構造連結串列

 根據遞迴定義,我們只需要一個Node型別的變數就能表示一條連結串列,只要保證它的值是null或者指向另一個Node物件且該物件的next域指向了另一條連結串列即可。

MyNode  first= new MyNode();

MyNode  second= new MyNode();

First.item =“a”;

Second.item = “b”;

First.next = second;

向連結串列中新增節點

先建立一個節點

MyNode<E> node

 = new MyNode<E>(item);

判斷條件

if(first==null){

//如果頭部為空

first = node ;

}else if(last !=null){

//如果尾部不為空

last.next = node;

}

最後size加一

last = node;

size++;

從連結串列中刪除節點

  刪除元素等要用到索引的地方,要先判斷是否角標越界。

if (index < 0 || index

 > size) {

try {

throw new Exception("角標越界");

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

在這裡可以丟擲一個異常。

MyNode<E> pre = first;

E result = null;

//得到目標的前一個元素

for(int i=0;i<index-1;i++){

pre = pre.next;

}

//如果刪除頭部

if(index==0){

result = first.item;

first = first.next;

pre = null;

}

//如果刪除尾部

else if(index==size-1){

result = last.item;

pre.next = null;

last = pre;

}

//如果刪除中間的

else{

MyNode<E> self = pre.next;

result = self.item;

pre.next = self.next;

self = null;

}

size--;

return result;

向連結串列中插入節點

MyNode<E> node = new MyNode<E>(item);

MyNode<E> pre = first;

for(int i=0;i<index1;i++){

pre = pre.next;

}

 //這裡判斷是否在頭部插入

 if(index2==0) {

          node.next = pre;

          first = node;

         }else {

          node.next = pre.next ;

      pre.next = node;

     node.item = item;

         }

 

        

size++;

改變元素

  MyNode<E> result = first;

for(int i = 0;i<index;i++){

//遍歷到當前的元素索引

result = result.next;

}

result.item = item;

得到元素

MyNode<E> result = first;

//遍歷到當前的元素索引

for(int i = 0;i<index;i++){

result = result.next;

}

 

return result.item;

上述介紹的是單向連結串列,雙向連結串列只不過比單向的多前驅和後繼而已。

新增節點(相對於單向連結串列)

if (last != null) {

 

last.next = node;

node.pre = last;

}

刪除節點

if (index == 0) {

result = first.item;

 

first = first.next;

first.pre = null;

}

else if (index == size - 1) {// 刪除尾部

// 找到最後一個元素。給結果值賦值

result = last.item;

before.next = null;

 

last = before;

} else {// 刪除中間的

// 首選要找到刪除節點

MyNode<E> self = before.next;

result = self.item;

before.next = self.next;

self.next.pre = before;

self = null;

 

}

插入節點

if (index == 0) {

myNode.next = before;

before.pre = myNode;

first = myNode;

size++;

} else {

myNode.next = before.next;

before.pre = myNode;

before.next = myNode;

myNode.pre = before;

 

}

 

二叉樹

 

樹:是由n(n>=1)個有限節點組成一個具有層次關係的集合

樹術語

節點度:一個節點含有子樹的個數稱為該節點的度

樹的度:一棵樹中,最大的節點的度為樹的度

葉子節點:度為零的節點

父親節點:若一個節點含有子節點,則當前節點為改子節點的父親節點

子節點:一個節點含有子樹,則子樹的根節點為改節點的子節點

兄弟節點:具有相同父親節點的子節點互為兄弟節點

節點層次:從根開始定義起,根為第1層,根的子節點為第2層,以此類推

樹的深度(高度):樹中節點最大的層次

其他:堂兄弟節點、子孫、森林

無序樹:樹中的節點次序是沒有規律的

有序樹:指樹中同層結點從左到右有次序排列,這樣的樹稱為有序樹。

 1)二叉樹:每個節點最多含有兩個子樹的樹稱為二叉樹

 2)非二叉樹:所有不是二叉樹的樹都屬於非二叉樹

二叉樹還分為完全二叉樹和滿二叉樹

滿二叉樹是二叉樹的父節點都有左孩子和右孩子

完全二叉樹是子節點呈左右左右排列

 

建立一棵樹首先要構建森林

要在另一個類中建立左右節點還有樹的值

TreeNode leftTree;

TreeNode rightTree;

int value;

構建森林

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

將元素裝到容器裡

TreeNode treenode = new TreeNode(arr[i]);

list.add(treenode);

}

構建除最後一個父節點其他的父節點和孩子

for(int i =0;i<list.size()/2-1;i++) {

list.get(i).setLeftTree(list.get(2*i+1));

list.get(i).setRightTree(list.get(2*i+2));

}

//將最後一個節點單獨處理

int lastIndex = list.size()/2-1;

list.get(lastIndex).setLeftTree(list.get(2*lastIndex+1));

//這裡是判斷是否為滿二叉樹

if(list.size()%2==1) {

list.get(lastIndex).setRightTree(list.get(2*lastIndex+2));

}

以上,一顆二叉樹構建完畢

樹的遍歷

先序遍歷樹

 先訪問根節點,然後訪問左子樹,最後訪問右子樹

將樹作為引數傳入方法中

public void beforeSearch(TreeNode tn) {

//根

System.out.println(tn.getValue());

//左

if(tn.getLeftTree()!=null) {

beforeSearch(tn.getLeftTree());

}

//右

if(tn.getRightTree()!=null) {

beforeSearch(tn.getRightTree());

}

}

中序遍歷樹

 先訪問左子樹,然後訪問根節點,最後訪問右子樹

public void midSearch(TreeNode tn) {

//左

if(tn.getLeftTree()!=null) {

midSearch(tn.getLeftTree());

}

//根

System.out.println(tn.getValue());

 

//右

if(tn.getRightTree()!=null) {

midSearch(tn.getRightTree());

}

}

後續遍歷樹

 先訪問左子樹,然後訪問右子樹,最後訪問根節點

public void lastSearch(TreeNode tn) {

//左

if(tn.getLeftTree()!=null) {

lastSearch(tn.getLeftTree());

}

//右

if(tn.getRightTree()!=null) {

lastSearch(tn.getRightTree());

}

//根

System.out.println(tn.getValue());

 

 

}