數據結構與算法

數據結構java

一、鏈表node

  由不定數量的節點(Node)組成,每一個節點僅知道下一個結點的位置,且向外僅僅暴露頭(head),一切操做直接或者間接從頭開始;算法

  代碼:單向鏈表的實現、鏈表反轉、鏈表中間點查詢、鏈表排序shell

  1.1單向鏈表的實現數組

 1 // 鏈表的實現
 2 public class Test {
 3     public static void main(String[] args) {
 4         NodeManager nodeManager = new NodeManager();
 5         nodeManager.addNode("大");
 6         nodeManager.addNode("家");
 7         nodeManager.addNode("好");
 8         nodeManager.addNode("才");
 9         nodeManager.addNode("是");
10         nodeManager.addNode("真");
11         nodeManager.addNode("的");
12         nodeManager.delNode("好");
13         nodeManager.print();
14     }
15 }
16 //節點管理類--封裝的增刪改
17 class NodeManager {
18 
19     private Node root;//根節點
20 
21     //添加節點
22     public void addNode(String data) {
23         if (root == null) {
24             root = new Node(data);
25         } else {
26             root.addNode(data);
27         }
28     }
29     //刪除節點
30     public void delNode (String data) {
31         if (root.data.equals(data)){
32             root = root.next;
33         } else {
34             root.delNode(data);
35         }
36     }
37     //打印節點
38     public void print() {
39         if (root != null) {
40             System.out.print(root.data + " ->");
41             root.print();
42         }
43     }
44 
45 
46 
47     // 節點類--節點結構和自帶簡易方法
48     class Node {
49         private String data;//數據源
50         private Node next;//指針域
51 
52         public Node(String data) {
53             this.data = data;
54         }
55         //添加方法
56         public void addNode(String data) {
57             if (this.next == null) {
58                 this.next = new Node(data);
59             } else {
60                 this.next.addNode(data);
61             }
62         }
63         //刪除方法
64         public void delNode(String name) {
65             if (this.next != null) {
66                 if (this.next.data.equals(name)) {
67                     this.next = this.next.next;
68                 } else {
69                     this.next.delNode(name);
70                 }
71             }
72         }
73         //打印方法
74         public void print() {
75             if (this.next != null) {
76                 System.out.print(this.next.data + "->");
77                 this.next.print();
78             }
79         }
80     }
81 }

1.2鏈表反轉數據結構

 1     /**
 2      * 鏈表反轉
 3      * 
 4      * @param head
 5      * @return
 6      */
 7     public Node ReverseIteratively(Node head) {
 8         Node pReversedHead = head;
 9         Node pNode = head;
10         Node pPrev = null;
11         while (pNode != null) {
12             Node pNext = pNode.next;
13             if (pNext == null) {
14                 pReversedHead = pNode;
15             }
16             pNode.next = pPrev;
17             pPrev = pNode;
18             pNode = pNext;
19         }
20         this.head = pReversedHead;
21         return this.head;
22     }

1.3鏈表中間點查詢post

 1 /**
 2  * 查找單鏈表的中間節點
 3  * 採用快慢指針的方式查找單鏈表的中間節點,快指針一次走兩步,慢指針一次走一步,當快指針走完時,慢指針恰好到達中間節點
 4  * @param head
 5  * @return
 6  */
 7 public Node SearchMid(Node head) {
 8     Node p = this.head, q = this.head;
 9     while (p != null && p.next != null && p.next.next != null) {
10         p = p.next.next;
11         q = q.next;
12     }
13     System.out.println("Mid:" + q.data);
14     return q;
15 }

1.4鏈表排序大數據

 1 /**
 2  * 排序
 3  * 用當前的node和隨後的全部的比較並進行位置互換,一波後挪一個節點
 4  * @return
 5  */
 6 public Node orderList() {
 7     Node nextNode = null;
 8     int tmp = 0;
 9     Node curNode = head;
10     while (curNode.next != null) {
11         nextNode = curNode.next;
12         while (nextNode != null) {
13             if (curNode.data > nextNode.data) {
14                 tmp = curNode.data;
15                 curNode.data = nextNode.data;
16                 nextNode.data = tmp;
17             }
18             nextNode = nextNode.next;
19         }
20         curNode = curNode.next;
21     }
22     return head;
23 }

 

二、隊列與棧ui

  棧:數據只能在棧的一端即棧頂位置進行插入和刪除操做;先進後出,後進先出this

  隊列:數據只能在隊列的一端插入並在另外一端進行刪除操做;先進先出

  代碼:棧的實現、隊列的實現

2.1棧的實現

 1 //棧的實現push和pop
 2 public void push(T data) {
 3     if (data==null){
 4         throw new StackException("data can't be null");
 5     }
 6     if(this.top==null){
 7         //調用pop()後top可能爲null
 8         this.top=new Node<T>(data);
 9     }else if(this.top.data==null){
10         this.top.data=data;
11     }else {
12         Node<T> p=new Node<T>(data,this.top);
13         top=p;
14         //更新棧頂
15     }
16     size++;
17 }
18 public T pop() {
19     if(isEmpty()){
20         throw new EmptyStackException("Stack empty");
21     }
22 
23     T data=top.data;
24     top=top.next;
25     size--;
26     return data;
27 }

 2.2隊列實現

 1  /** 
 2  * 隊列入隊算法 
 3  * @param data 
 4  * @author WWX 
 5  */  
 6 public void enqueue(T data){  
 7     //建立一個節點  
 8     Node s=new Node(data,null);  
 9     //將隊尾指針指向新加入的節點,將s節點插入隊尾  
10     rear.next=s;  
11     rear=s;  
12     size++;  
13 }  
14   
15 /** 
16  * 隊列出隊算法 
17  * @return 
18  * @author WWX 
19  */  
20 public  T dequeue(){  
21     if(rear==front){  
22         try {  
23             throw new Exception("堆棧爲空");  
24         } catch (Exception e) {  
25             e.printStackTrace();  
26         }  
27         return null;  
28     }else{  
29         //暫存隊頭元素  
30         Node p=front.next;  
31         T x=p.data;  
32         //將隊頭元素所在節點摘鏈  
33         front.next=p.next;  
34         //判斷出隊列長度是否爲1  
35         if(p.next==null)  
36             rear=front;  
37         //刪除節點  
38         p=null;  
39         size--;  
40         return  x;  
41     }  
42 }  

 三、二叉樹

  二叉樹:N個結點構成的有限集合;每一個結點至多隻有兩棵子樹(即二叉樹中不存在度大於2的結點),而且,二叉樹的子樹有左右之分,其次序不能任意顛倒

  特性:    (1)若根結點的層次爲1,則二叉樹第i層最多有2i1(i1)個結點;在高度爲h的二叉樹中,最多有2h1個結點(h≥0);

      (2)滿二叉樹和徹底二叉樹 

      (3) 一棵具備n個結點的徹底二叉樹,對於序號爲i(0≤i<n)的結點,則有以下規則 
        ①若i=0,則i爲根結點,無父母結點;若i>0,則i的父母結點序號爲i12(向下取整)。 
        ②若2i+1<n,則i的左孩子結點序號爲2i+1,不然i無左孩子。 
        ③若2i+2>n,則i的右孩子結點序號爲2i+2,不然i無右孩子。 

               

  代碼:二叉樹實現、遍歷

  3.1二叉樹實現

 1 // 二叉樹數據結構的實現
 2 public class Test {
 3     public static void main(String[] args) {
 4         BinaryTreeManger binaryTreeManger = new BinaryTreeManger();
 5 
 6         binaryTreeManger.add(1);
 7         binaryTreeManger.add(3);
 8         binaryTreeManger.add(4);
 9         binaryTreeManger.add(8);
10         binaryTreeManger.add(6);
11         binaryTreeManger.print();
12     }
13 }
14 
15 class BinaryTreeManger{
16 
17     private Node root;//根節點
18 
19     public void add(int data) {
20         if (root == null) {
21             root = new Node(data);
22         } else {
23             root.addNode(data);
24         }
25     }
26     public void print() {
27         root.print();
28     }
29     class Node{
30         private int data;
31         private Node left; //左子樹
32         private Node right; //右子樹
33 
34         public Node(int data) {
35             this.data = data;
36         }
37         //添加節點
38         public void addNode(int data) {
39             //首先判斷大小,來決定將data放在那個子樹上
40             if (data > this.data){//當前數據較大,放在右子樹
41                 if (this.right == null) {
42                     this.right = new Node(data);
43                 } else {
44                     this.right.addNode(data);
45                 }
46             } else { //較小放在左子樹上
47                 if (this.left == null) {
48                     this.left = new Node(data);
49                 } else {
50                     this.left.addNode(data);
51                 }
52 
53             }
54 
55         }
56         //中序遍歷 左 -> 根 -> 右
57         public void print() {
58             if (this.left != null) {
59                 this.left.print();
60             }
61             System.out.print(data);
62             if (this.right != null) {
63                 this.right.print();
64             }
65         }
66     }
67 }

3.2二叉樹遍歷

 1 public void visted(TreeNode subTree){  
 2     subTree.isVisted=true;  
 3     System.out.println("key:"+subTree.key+"--name:"+subTree.data);;  
 4 }  
 5 //前序遍歷   
 6 public void preOrder(TreeNode subTree){  
 7     if(subTree!=null){  
 8         visted(subTree);  
 9         preOrder(subTree.leftChild);  
10         preOrder(subTree.rightChild);  
11     }  
12 }  
13   
14 //中序遍歷   
15 public void inOrder(TreeNode subTree){  
16     if(subTree!=null){  
17         inOrder(subTree.leftChild);  
18         visted(subTree);  
19         inOrder(subTree.rightChild);  
20     }  
21 }  
22   
23 //後續遍歷   
24 public void postOrder(TreeNode subTree) {  
25     if (subTree != null) {  
26         postOrder(subTree.leftChild);  
27         postOrder(subTree.rightChild);  
28         visted(subTree);  
29     }  
30 }  
31   
32 //前序遍歷的非遞歸實現   
33 public void nonRecPreOrder(TreeNode p){  
34     Stack<TreeNode> stack=new Stack<TreeNode>();  
35     TreeNode node=p;  
36     while(node!=null||stack.size()>0){  
37         while(node!=null){  
38             visted(node);  
39             stack.push(node);  
40             node=node.leftChild;  
41         }  
42         while(stack.size()>0){  
43             node=stack.pop();  
44             node=node.rightChild;  
45         }   
46     }  
47 }  
48   
49 //中序遍歷的非遞歸實現   
50 public void nonRecInOrder(TreeNode p){  
51     Stack<TreeNode> stack =new Stack<BinaryTree.TreeNode>();  
52     TreeNode node =p;  
53     while(node!=null||stack.size()>0){  
54         //存在左子樹   
55         while(node!=null){  
56             stack.push(node);  
57             node=node.leftChild;  
58         }  
59         //棧非空   
60         if(stack.size()>0){  
61             node=stack.pop();  
62             visted(node);  
63             node=node.rightChild;  
64         }  
65     }  
66 }  
67   
68 //後序遍歷的非遞歸實現   
69 public void noRecPostOrder(TreeNode p){  
70     Stack<TreeNode> stack=new Stack<BinaryTree.TreeNode>();  
71     TreeNode node =p;  
72     while(p!=null){  
73         //左子樹入棧   
74         for(;p.leftChild!=null;p=p.leftChild){  
75             stack.push(p);  
76         }  
77         //當前結點無右子樹或右子樹已經輸出   
78         while(p!=null&&(p.rightChild==null||p.rightChild==node)){  
79             visted(p);  
80             //紀錄上一個已輸出結點   
81             node =p;  
82             if(stack.empty())  
83                 return;  
84             p=stack.pop();  
85         }  
86         //處理右子樹   
87         stack.push(p);  
88         p=p.rightChild;  
89     }  
90 }  

借鑑博客(版權已被聲明):http://blog.csdn.net/javazejian/article/details/53727333

四、其餘

  串:若干個字符組成的有限序列;

  數組:有限個類型相同的變量的集合;

  廣義表:若干個元素組成的有限序列;

 

排序算法

各類排序算法時間複雜度和空間複雜度

一、插入排序

  插入排序:穩定,最好最壞均爲O(n2);

  原理:拿要後邊要排序元素與前邊已經排好的元素進行比較,從後向前掃描,找到位置並插入;

  shell排序:不穩定,平均O(n1.5),最壞O(n2);

  原理:數據等距離分組,組內插入排序;分組距離減半,組內繼續插入排序....

  1.1插入排序

1 for (int i = 0; i < len; i++) {
2     for (int j = i + 1; j < len && j > 0; j--) {
3         if (a[j] < a[j - 1]) {
4             int temp = a[j];
5             a[j] = a[j - 1];
6             a[j - 1] = temp;
7         }
8     }
9 }

   1.2shell排序

 1 int group, i, j, temp,len;
 2 len = unsorted.length;
 3 for (group = len / 2; group > 0; group /= 2)
 4 {
 5     for (i = group; i < len; i++)
 6     {
 7         for (j = i - group; j >= 0; j -= group)
 8         {
 9             if (unsorted[j] > unsorted[j + group])
10             {
11                 temp = unsorted[j];
12                 unsorted[j] = unsorted[j + group];
13                 unsorted[j + group] = temp;
14             }
15         }
16     }
17 }

二、選擇排序

  直接選擇:不穩定,最好最壞均爲O(n2);

  原理:每次從當前位置到最末尾,獲取最小數據互換到當前位置,並依次後移

  堆排序:不穩定,最好最壞均爲O(nlog2n);

  原理:徹底二叉樹,大頂堆(父節點大於等於子節點),小頂堆(父節點小於等於子節點);

  數據構建徹底二叉樹->大頂堆->根節點換到葉子節點左右側(把最大數據放到最後)->大頂堆->根節點換到葉子節點左右側(再次把第二大數據放到最後第二位置)....

  2.1直接選擇

 1 //min 記錄最小數據,index記錄最小位置
 2 int min = 0;
 3 int index = 0;
 4 int len = a.length;
 5 for (int i = 0; i < len - 1; i++) {
 6     min = a[i];
 7     index = i;
 8     for (int j = i + 1; j < len; j++) {
 9         if (a[j] < min) {
10             min = a[j];
11             index = j;
12         }
13     }
14     a[index] = a[i];
15     a[i] = min;
16 }

  2.2堆排序

 1 //調整堆 
 2 void HeapAdjust(int *a,int i,int size)  
 3 {
 4     int lchild=2*i;       //i的左孩子節點序號 
 5     int rchild=2*i+1;     //i的右孩子節點序號 
 6     int max=i;            //臨時變量 
 7     if(i<=size/2)         //若是i是葉節點就不用進行調整 
 8     {
 9         if(lchild<=size&&a[lchild]>a[max])
10         {
11             max=lchild;
12         }    
13         if(rchild<=size&&a[rchild]>a[max])
14         {
15             max=rchild;
16         }
17         if(max!=i)
18         {
19             swap(a[i],a[max]);
20             HeapAdjust(a,max,size);    //避免調整以後以max爲父節點的子樹不是堆 
21         }
22     }        
23 }
24 void BuildHeap(int *a,int size)    //創建堆 
25 {
26     int i;
27     for(i=size/2;i>=1;i--)    //非葉節點最大序號值爲size/2 
28     {
29         HeapAdjust(a,i,size);    
30     }    
31 } 
32 void HeapSort(int *a,int size)    //堆排序 
33 {
34     int i;
35     BuildHeap(a,size);
36     for(i=size;i>=1;i--)
37     {
38         swap(a[1],a[i]);           //交換堆頂和最後一個元素,即每次將剩餘元素中的最大者放到最後面 
39         HeapAdjust(a,1,i-1);      //從新調整堆頂節點成爲大頂堆
40     }
41 }

 

三、交換排序

  冒泡排序:穩定,平均最壞均爲O(n2);

  原理:重複走訪數據,每加入一次數據,從該位置起,相鄰數據兩兩比較,位置互換;

  快速排序:不穩定,平均爲O(nlog2n),最壞爲O(n2);

  原理:將數據分隔成兩部分,左邊<key<右邊,依次遞歸,縮小範圍

  3.1冒泡排序

1 //j與j+1相鄰比較
2 for(int i = 0; i < len-1; i++){
3     for (int j = 0; j > len-i; j++){
4         if (array[j] < array[j+1] ){
5             swap(array,j,j+1);
6         }
7     }
8 }

  3.2快速排序

 1  public void sort(int[] a,int low,int high){
 2      int start = low;
 3      int end = high;
 4      int key = a[low];
 5      
 6      
 7      while(end>start){
 8          //從後往前比較
 9          //若是沒有比關鍵值小的,比較下一個,直到有比關鍵值小的交換位置,而後又從前日後比較
10          while(end>start&&a[end]>=key)  
11              end--;
12          if(a[end]<=key){
13              int temp = a[end];
14              a[end] = a[start];
15              a[start] = temp;
16          }
17          //從前日後比較
18          //若是沒有比關鍵值大的,比較下一個,直到有比關鍵值大的交換位置
19          while(end>start&&a[start]<=key)
20             start++;
21          if(a[start]>=key){
22              int temp = a[start];
23              a[start] = a[end];
24              a[end] = temp;
25          }
26      //此時第一次循環比較結束,關鍵值的位置已經肯定了。
27      //左邊的值都比關鍵值小,右邊的值都比關鍵值大,
28      //可是兩邊的順序還有多是不同的,進行下面的遞歸調用
29      }
30      //遞歸
31      if(start>low) sort(a,low,start-1);//左邊序列。第一個索引位置到關鍵值索引-1
32      if(end<high) sort(a,end+1,high);//右邊序列。從關鍵值索引+1到最後一個
33 }

四、歸併排序

五、基數排序

 

平均O(n3/2),最壞O(n2)

相關文章
相關標籤/搜索