Dsa Using Java 简明教程

DSA using Java - Quick Guide

DSA using Java - Overview

What is a Data Structure?

数据结构是组织数据的一种方法,可以有效地利用数据。以下术语是数据结构的基础术语。

  1. Interface − 每个数据结构都有一个接口。接口表示数据结构支持的操作集合。接口仅提供支持操作的列表、可以接受的参数类型和这些操作的返回类型。

  2. Implementation − 实现提供了数据结构的内部表示形式。实现还提供了数据结构操作中使用的算法定义。

Characteristics of a Data Structure

  1. Correctness − 数据结构实现应正确地实现其接口。

  2. Time Complexity − 数据结构操作的运行时间或执行时间必须尽可能小。

  3. Space Complexity − 数据结构操作的内存使用量应尽可能小。

Need for Data Structure

随着应用程序变得复杂且数据丰富,如今应用程序面临三个常见问题。

  1. Data Search − 考虑一家商店有 100 万 (106) 件库存。如果应用程序要搜索一个项目。它必须在 100 万 (106) 个项目中每次搜索一个项目,从而降低搜索速度。随着数据增长,搜索将变得更加缓慢。

  2. Processor speed − 处理器速度虽然很高,但如果数据增长到几十亿条记录,就会受到限制。

  3. Multiple requests − 由于数千名用户可以在 Web 服务器上同时搜索数据,因此即使非常快的服务器在搜索数据时也会遇到故障。

为了解决上述问题,数据结构派上了用场。可以将数据组织到数据结构中,使得可能无需搜索所有项目,并且可以几乎立即搜索所需数据。

Execution Time Cases

有三个案例通常用于以相对的方式比较各种数据结构的执行时间。

  1. Worst Case − 这是特定数据结构操作花费最多时间的情况。如果一个操作的最坏情况时间是 ƒ(n),那么这个操作不会花费超过 ƒ(n) 次时间,其中 ƒ(n) 表示 n 的函数。

  2. Average Case − 这是描述数据结构操作的平均执行时间的情况。如果一个操作执行时间为 ƒ(n),那么 m 个操作将花费 mƒ(n) 时间。

  3. Best Case − 这是描述数据结构操作最可能的执行时间的情况。如果一个操作执行时间为 ƒ(n),那么实际操作可能需要的时间是一个随机数,该随机数最多为 ƒ(n)。

DSA using Java - Environment Setup

Local Environment Setup

如果您仍希望为Java编程语言设置环境,那么本部分将指导您如何在机器上下载和设置Java。请按照以下步骤设置环境。

Java SE 可以从链接 Download Java 中免费获取。因此,您可以根据自己的操作系统下载版本。

按照说明下载 Java 并运行 .exe 以在你的计算机上安装 Java。一旦在计算机上安装了 Java,就需要设置环境变量以指向正确的安装目录:

Setting up the path for windows 2000/XP

假设你已将 Java 安装在 c:\Program Files\java\jdk 目录中:

  1. 右键单击“我的电脑”,然后选择“属性”。

  2. 单击“高级”选项卡下的“环境变量”按钮。

  3. 现在更改“路径”变量,使其还包含 Java 可执行文件的路径。例如,如果路径当前设置为“C:\WINDOWS\SYSTEM32”,则将路径更改为“C:\WINDOWS\SYSTEM32;c:\Program Files\java\jdk\bin”。

Setting up the path for windows 95/98/ME

假设你已将 Java 安装在 c:\Program Files\java\jdk 目录中 −

  1. 编辑 'C:\autoexec.bat' 文件并在末尾添加以下行:'SET PATH=%PATH%;C:\Program Files\java\jdk\bin'

Setting up the path for Linux, UNIX, Solaris, FreeBSD:

环境变量 PATH 应设置为指向已安装 Java 二进制文件的位置。如果您在执行此操作时遇到问题,请参阅您的 shell 文档。

例如,如果您用 bash 作为您的 shell,则您将向您 '.bashrc: export PATH=/path/to/java:$PATH' 的末尾添加以下行

要编写 Java 程序,您需要一个文本编辑器。市场上还有一些更复杂的 IDE,但目前,您可以考虑以下选项之一:

  1. Notepad − 在Windows计算机上可以使用任何简单的文本编辑器,如记事本(建议用于本教程)、TextPad。

  2. *Netbeans −*是一个Java IDE,它开源且免费,可以从 https://www.netbeans.org/index.html 下载。

  3. Eclipse − 也是由eclipse开源社区开发的一个Java IDE,可以从 https://www.eclipse.org/ 下载。

What is Next ?

下一章将教您如何编写和运行您的第一个Java程序以及一些用于开发应用程序所需的Java中的重要基础语法。

DSA using Java - Algorithms

Algorithm concept

算法是一个按步骤执行的过程,其中定义了一组要以特定顺序执行的指令以获取所需的输出。在数据结构方面,以下是对算法的分类。

  1. Search − 搜索数据结构中某个项的算法。

  2. Sort − 按特定顺序对项进行排序的算法

  3. Insert − 将项插入数据结构中的算法

  4. Update − 更新数据结构中现有项的算法

  5. Delete − 从数据结构中删除现有项的算法

Algorithm analysis

算法分析涉及到数据结构执行时间或各种操作的运行时间。操作的运行时间可定义为:每个操作执行的计算机指令数。由于任何操作的确切运行时间因计算机不同而异,我们通常会分析任何操作的运行时间作为 n 的某个函数,其中 n 为该操作在数据结构中处理的项数。

Asymptotic analysis

渐近分析是指以计算单位计算任何操作的运行时间。例如,某个操作的运行时间计算为 f(n),而另一个操作的运行时间计算为 g(n2)。这意味着第一个操作的运行时间将随着 n 的增加而线性增加,而第二个操作的运行时间将在 n 增加时呈指数级增加。同样,如果 n 非常小,则两个操作的运行时间将几乎相同。

Asymptotic Notations

以下是用于计算算法运行时间复杂度的常用渐近符号。

  1. Ο Notation

  2. Ω Notation

  3. θ Notation

Big Oh Notation, Ο

大 O 符号用于简化函数。例如,我们可以用 Ο(f(nlogn)) 替换特定的函数方程 7nlogn + n - 1。考虑如下情况:

它表明 f(n) = 7nlogn + n - 1 在 O(nlogn) 的输出范围内,常数 c = 8 且 n0 = 2。

Omega Notation, Ω

Ω(n) 是表达算法运行时间下界的正式方法。它衡量算法可能完成的最佳情况时间复杂度或最佳时间量。

例如,对于一个函数 f(n)

Theta Notation, θ

θ(n) 是表达算法运行时间的上下界的正式方法。它表示如下。

DSA using Java - Data Structures

数据结构是用一种有效的方式组织数据的方法。以下术语是数据结构的基本术语。

Data Definition

数据定义用以下特征定义特定数据。

  1. 原子性 − 定义应该定义单个概念

  2. 可追踪性 − 定义应该是能够映射到某些数据元素的。

  3. 准确性 − 定义应该是明确的。

  4. 清晰简洁性 − 定义应该是可以理解的。

Data Object

数据对象表示具有数据的一个对象。

Data Type

数据类型是指对各种类型的数据(如整数、字符串等)进行分类的方法,它决定了可与相应类型的数据一起使用的数据类型,以及可在相应类型的数据上执行的操作类型。数据类型有两种类型−

  1. Built-in Data Type

  2. Derived Data Type

Built-in Data Type

语言内置支持的那些数据类型称为内置数据类型。例如,大多数语言提供以下内置数据类型。

  1. Integers

  2. Boolean (true, false)

  3. Floating (Decimal numbers)

  4. Character and Strings

Derived Data Type

那些实现独立的数据类型,因为它们可以以一种或另一种方式实现,被称为派生数据类型。这些数据类型通常是通过组合主数据类型或内置数据类型以及对它们的关联操作来构建的。例如 −

  1. List

  2. Array

  3. Stack

  4. Queue

DSA using Java - Arrays

Array Basics

数组是一个容器,可以容纳固定数量的项,并且这些项应为同类型。大多数数据结构使用数组来实现其算法。以下是理解数组概念的重要术语

  1. Element - 存储在数组中的每个项称为一个元素。

  2. Index − 数组中每个元素的位置都有一个数字索引,该索引用于标识该元素。

Array Representation

array

根据以上所示的说明,以下是要考虑的重要要点。

  1. Index starts with 0.

  2. 数组长度为 8,这意味着它可以存储 8 个元素。

  3. 可以通过它们的索引访问每个元素。例如,我们可以获取索引为 6 的元素 9。

Basic Operations

数组支持的基本操作如下。

  1. Insertion − 在给定索引处添加一个元素。

  2. Deletion − 在给定索引处删除一个元素。

  3. Search − 使用给定索引或按值搜索一个元素。

  4. Update − 在给定索引处更新一个元素。

在 java 中,当使用大小初始化一个数组时,它会按以下顺序为其元素分配默认值。

Data Type

Default Value

byte

0

short

0

int

0

long

0L

float

0.0f

double

0.0d

char

'\u0000'

boolean

false

Object

null

Demo

package com.tutorialspoint.array;

public class ArrayDemo {
   public static void main(String[] args){

      // Declare an array
      int intArray[];

      // Initialize an array of 8 int
      // set aside memory of 8 int
      intArray = new int[8];

      System.out.println("Array before adding data.");

      // Display elements of an array.
      display(intArray);

      // Operation : Insertion
      // Add elements in the array
      for(int i = 0; i< intArray.length; i++)
      {
         // place value of i at index i.
         System.out.println("Adding "+i+" at index "+i);
         intArray[i] = i;
      }
      System.out.println();

      System.out.println("Array after adding data.");
      display(intArray);

      // Operation : Insertion
      // Element at any location can be updated directly
      int index = 5;
      intArray[index] = 10;

      System.out.println("Array after updating element at index " + index);
      display(intArray);

      // Operation : Search using index
      // Search an element using index.
      System.out.println("Data at index " + index + ": "+ intArray[index]);

      // Operation : Search using value
      // Search an element using value.
      int value = 4;
      for(int i = 0; i< intArray.length; i++)
      {
         if(intArray[i] == value ){
            System.out.println(value + " Found at index "+i);
            break;
         }
      }
      System.out.println("Data at index " + index + ": "+ intArray[index]);
   }

   private static void display(int[] intArray){
      System.out.print("Array : [");
      for(int i = 0; i< intArray.length; i++)
      {
         // display value of element at index i.
         System.out.print(" "+intArray[i]);
      }
      System.out.println(" ]");
      System.out.println();
   }
}

如果我们编译并运行上述程序,它将生成以下结果 -

Array before adding data.
Array : [ 0 0 0 0 0 0 0 0 ]

Adding 0 at index 0
Adding 1 at index 1
Adding 2 at index 2
Adding 3 at index 3
Adding 4 at index 4
Adding 5 at index 5
Adding 6 at index 6
Adding 7 at index 7

Array after adding data.
Array : [ 0 1 2 3 4 5 6 7 ]

Array after updating element at index 5
Array : [ 0 1 2 3 4 10 6 7 ]

Data at index 5: 10
4 Found at index: 4

DSA using Java - Linked List

Linked List Basics

链表是由包含项的链接序列。每个链接都包含到另一个链接的连接。链表是在数组之后使用第二多的数据结构。以下是理解链表概念的重要术语。

  1. Link − 链表的每个链接可以存储一个称为元素的数据。

  2. Next − 链表的每个链接都包含到下一个链接的链接,称为 Next。

  3. LinkedList − 一个 LinkedList 包含连接到称为 First 的第一个 Link 的连接链接。

Linked List Representation

dsa linkedlist

根据以上所示的说明,以下是要考虑的重要要点。

  1. 双向链表包含第一个链接元素。

  2. 每个链接都包含一个数据字段(多个字段)和一个称为 Next 的链接字段。

  3. 每个链接使用其 Next 链接与其下一个链接链接。

  4. 最后一个链接包含一个空链接来标记链表的结尾。

Types of Linked List

以下是双向链表的各种类型。

  1. Simple Linked List - 项目导航仅向前。

  2. Doubly Linked List - 项目可以向前和向后导航。

  3. Circular Linked List - 最后一个项目包含第一个元素的链接,而第一个元素包含指向最后一个元素的链接。

Basic Operations

以下是列表支持的基本操作。

  1. Insertion − 在链表的开头添加元素。

  2. Deletion − 删除链表开头的元素。

  3. Display - 显示完整的列表。

  4. Search - 使用给定的键搜索元素。

  5. Delete - 使用给定的键删除元素。

Insertion Operation

插入是一个三步过程:

dsa linkedlist insertfirst
//insert link at the first location
public void insertFirst(int key, int data){
   //create a link
   Link link = new Link(key,data);
   //point it to old first node
   link.next = first;
   //point first to new first node
   first = link;
}

Deletion Operation

删除是一个两步过程:

dsa linkedlist deletefirst
//delete first item
public Link deleteFirst(){
   //save reference to first link
   Link tempLink = first;
   //mark next to first link as first
   first = first.next;
   //return the deleted link
   return tempLink;
}

Navigation Operation

导航是一个递归步骤过程,是许多操作(如搜索、删除等)的基础:

dsa linkedlist navigation

Note

//display the list
public void display(){
   //start from the beginning
   Link current = first;
   //navigate till the end of the list
   System.out.print("[ ");
   while(current != null){
      //print data
      current.display();
      //move to next item
      current = current.next;
      System.out.print(" ");
   }
   System.out.print(" ]");
}

Advanced Operations

以下是为列表指定的高级操作。

  1. Sort - 根据特定顺序对列表进行排序。

  2. Reverse - 逆转链表。

  3. Concatenate - 连接两个列表。

Sort Operation

我们使用冒泡排序对列表进行排序。

public void sort(){

   int i, j, k, tempKey, tempData ;
   Link current,next;
   int size = length();
   k = size ;
   for ( i = 0 ; i < size - 1 ; i++, k-- ) {
      current = first ;
      next = first.next ;
      for ( j = 1 ; j < k ; j++ ) {
         if ( current.data > next.data ) {
            tempData = current.data ;
            current.data = next.data;
            next.data = tempData ;

            tempKey = current.key;
            current.key = next.key;
            next.key = tempKey;
         }
         current = current.next;
         next = next.next;
      }
   }
}

Reverse Operation

以下代码演示如何逆转一个单链表。

public LinkedList reverse() {
   LinkedList reversedlist = new LinkedList();
   Link nextLink = null;
   reversedlist.insertFirst(first.key, first.data);

   Link currentLink = first;
   // Until no more data in list,
   // insert current link before first and move ahead.
   while(currentLink.next != null){
      nextLink = currentLink.next;
      // Insert at start of new list.
      reversedlist.insertFirst(nextLink.key, nextLink.data);
      //advance to next node
      currentLink = currentLink.next;
   }
   return reversedlist;
}

Concatenate Operation

以下代码演示如何逆转一个单链表。

public void concatenate(LinkedList list){
   if(first == null){
      first = list.first;
   }
   if(list.first == null){
      return;
   }
   Link temp = first;
   while(temp.next !=null) {
      temp = temp.next;
   }
   temp.next = list.first;
}

Demo

package com.tutorialspoint.list;

public class Link {
   public int key;
   public int data;
   public Link next;

   public Link(int key, int data){
      this.key = key;
      this.data = data;
   }

   public void display(){
      System.out.print("{"+key+","+data+"}");
   }
}
package com.tutorialspoint.list;

public class LinkedList {
   //this link always point to first Link
   //in the Linked List
   private Link first;

   // create an empty linked list
   public LinkedList(){
      first = null;
   }

   //insert link at the first location
   public void insertFirst(int key, int data){
      //create a link
      Link link = new Link(key,data);
      //point it to old first node
      link.next = first;
      //point first to new first node
      first = link;
   }

   //delete first item
   public Link deleteFirst(){
      //save reference to first link
      Link tempLink = first;
      //mark next to first link as first
      first = first.next;
      //return the deleted link
      return tempLink;
   }

   //display the list
   public void display(){
      //start from the beginning
      Link current = first;
      //navigate till the end of the list
      System.out.print("[ ");
      while(current != null){
         //print data
         current.display();
         //move to next item
         current = current.next;
         System.out.print(" ");
      }
      System.out.print(" ]");
   }

   //find a link with given key
   public Link find(int key){
      //start from the first link
      Link current = first;

      //if list is empty
      if(first == null){
         return null;
      }
      //navigate through list
      while(current.key != key){
         //if it is last node
         if(current.next == null){
            return null;
         }else{
            //go to next link
            current = current.next;
         }
      }
      //if data found, return the current Link
      return current;
   }

   //delete a link with given key
   public Link delete(int key){
      //start from the first link
      Link current = first;
      Link previous = null;
      //if list is empty
      if(first == null){
         return null;
      }

      //navigate through list
      while(current.key != key){
         //if it is last node
         if(current.next == null){
            return null;
         }else{
            //store reference to current link
            previous = current;
            //move to next link
            current = current.next;
         }
      }

      //found a match, update the link
      if(current == first) {
         //change first to point to next link
         first = first.next;
      }else {
         //bypass the current link
         previous.next = current.next;
      }
      return current;
   }


   //is list empty
   public boolean isEmpty(){
      return first == null;
   }

   public int length(){
      int length = 0;
      for(Link current = first; current!=null;
         current = current.next){
         length++;
      }
      return length;
   }

   public void sort(){
      int i, j, k, tempKey, tempData ;
      Link current,next;
      int size = length();
      k = size ;
      for ( i = 0 ; i < size - 1 ; i++, k-- ) {
         current = first ;
         next = first.next ;
         for ( j = 1 ; j < k ; j++ ) {
            if ( current.data > next.data ) {
               tempData = current.data ;
               current.data = next.data;
               next.data = tempData ;

	           tempKey = current.key;
	           current.key = next.key;
	           next.key = tempKey;
            }
            current = current.next;
           next = next.next;
         }
      }
   }

   public LinkedList reverse() {
      LinkedList reversedlist = new LinkedList();
      Link nextLink = null;
      reversedlist.insertFirst(first.key, first.data);

      Link currentLink = first;
      // Until no more data in list,
      // insert current link before first and move ahead.
      while(currentLink.next != null){
         nextLink = currentLink.next;
         // Insert at start of new list.
         reversedlist.insertFirst(nextLink.key, nextLink.data);
         //advance to next node
         currentLink = currentLink.next;
      }
      return reversedlist;
   }

   public void concatenate(LinkedList list){
      if(first == null){
         first = list.first;
      }
      if(list.first == null){
         return;
      }
      Link temp = first;

      while(temp.next !=null) {
         temp = temp.next;
      }
      temp.next = list.first;
   }
}
package com.tutorialspoint.list;

public class LinkedListDemo {
   public static void main(String args[]){
      LinkedList list = new LinkedList();

      list.insertFirst(1, 10);
      list.insertFirst(2, 20);
      list.insertFirst(3, 30);
      list.insertFirst(4, 1);
      list.insertFirst(5, 40);
      list.insertFirst(6, 56);

      System.out.print("\nOriginal List: ");
      list.display();
      System.out.println("");
      while(!list.isEmpty()){
         Link temp = list.deleteFirst();
         System.out.print("Deleted value:");
         temp.display();
         System.out.println("");
      }
      System.out.print("List after deleting all items: ");
      list.display();
      System.out.println("");
      list.insertFirst(1, 10);
      list.insertFirst(2, 20);
      list.insertFirst(3, 30);
      list.insertFirst(4, 1);
      list.insertFirst(5, 40);
      list.insertFirst(6, 56);

      System.out.print("Restored List: ");
      list.display();
      System.out.println("");

      Link foundLink = list.find(4);
      if(foundLink != null){
        System.out.print("Element found: ");
         foundLink.display();
         System.out.println("");
      }else{
         System.out.println("Element not found.");
      }

      list.delete(4);
      System.out.print("List after deleting an item: ");
      list.display();
      System.out.println("");
      foundLink = list.find(4);
      if(foundLink != null){
         System.out.print("Element found: ");
         foundLink.display();
         System.out.println("");
      }else{
         System.out.print("Element not found. {4,1}");
      }
      System.out.println("");
      list.sort();
      System.out.print("List after sorting the data: ");
      list.display();
      System.out.println("");
      System.out.print("Reverse of the list: ");
      LinkedList list1 = list.reverse();
      list1.display();
      System.out.println("");

      LinkedList list2 = new LinkedList();

      list2.insertFirst(9, 50);
      list2.insertFirst(8, 40);
      list2.insertFirst(7, 20);

      list.concatenate(list2);
      System.out.print("List after concatenation: ");
      list.display();
      System.out.println("");
   }
}

如果我们编译并运行上面的程序,它将产生以下结果:

Original List: [ {6,56} {5,40} {4,1} {3,30} {2,20} {1,10}  ]
Deleted value:{6,56}
Deleted value:{5,40}
Deleted value:{4,1}
Deleted value:{3,30}
Deleted value:{2,20}
Deleted value:{1,10}
List after deleting all items: [  ]
Restored List: [ {6,56} {5,40} {4,1} {3,30} {2,20} {1,10}  ]
Element found: {4,1}
List after deleting an item: [ {6,56} {5,40} {3,30} {2,20} {1,10}  ]
Element not found. {4,1}
List after sorting the data: [ {1,10} {2,20} {3,30} {5,40} {6,56}  ]
Reverse of the list: [ {6,56} {5,40} {3,30} {2,20} {1,10}  ]
List after concatenation: [ {1,10} {2,20} {3,30} {5,40} {6,56} {7,20} {8,40} {9,50}  ]

DSA using Java - Doubly Linked List

Doubly Linked List Basics

双向链表是链表的一种变体,与单向链表相比,它可以在两个方向(向前或向后)轻松地导航。以下是理解双向链表概念的重要术语

  1. Link − 链表的每个链接可以存储一个称为元素的数据。

  2. Next − 链表的每个链接都包含到下一个链接的链接,称为 Next。

  3. Prev − 链表的每个链接都包含到前一个链接的链接,称为 Prev。

  4. LinkedList − 一个 LinkedList 包含指向第一个称为 First 的链接的链接链接和指向最后一个链接(称为 Last)的链接链接。

Doubly Linked List Representation

dsa doublylinkedlist

根据以上所示的说明,以下是要考虑的重要要点。

  1. 双重 LinkedList 包含一个称为 First 和 Last 的链元素。

  2. 每个链接都包含一个数据字段(多个字段)和一个称为 Next 的链接字段。

  3. 每个链接使用其 Next 链接与其下一个链接链接。

  4. 每个链接使用其 Prev 链接与其上一个链接链接。

  5. 最后一个链接包含一个空链接来标记链表的结尾。

Basic Operations

以下是由链表支持的基本操作。

  1. Insertion − 在链表的开头添加元素。

  2. Deletion − 删除链表开头的元素。

  3. Insert Last − 在链表的末尾添加元素。

  4. Delete Last − 从链表的末尾删除元素。

  5. Insert After − 在链表项后添加元素。

  6. Delete − 使用键从链表删除元素。

  7. Display forward − 以正向方式显示完整链表。

.

  1. Display backward − 以反向方式显示完整链表。

Insertion Operation

以下代码演示在双向链表的开头执行插入操作。

//insert link at the first location
public void insertFirst(int key, int data){
   //create a link
   Link link = new Link(key,data);

   if(isEmpty()){
      //make it the last link
      last = link;
   }else {
      //update first prev link
      first.prev = link;
   }

   //point it to old first link
   link.next = first;
   //point first to new first link
   first = link;
}

Deletion Operation

以下代码演示在双向链表的开头执行删除操作。

//delete link at the first location
public Link deleteFirst(){
   //save reference to first link
   Link tempLink = first;
   //if only one link
   if(first.next == null){
      last = null;
   }else {
      first.next.prev = null;
   }
   first = first.next;
   //return the deleted link
   return tempLink;
}

Insertion at End Operation

以下代码演示在双向链表的末尾执行插入操作。

//insert link at the last location
public void insertLast(int key, int data){
   //create a link
   Link link = new Link(key,data);

   if(isEmpty()){
      //make it the last link
      last = link;
   }else {
      //make link a new last link
      last.next = link;
      //mark old last node as prev of new link
      link.prev = last;
   }

   //point last to new last node
   last = link;
}

Demo

Link.java

package com.tutorialspoint.list;

public class Link {
   public int key;
   public int data;
   public Link next;
   public Link prev;

   public Link(int key, int data){
      this.key = key;
      this.data = data;
   }

   public void display(){
      System.out.print("{"+key+","+data+"}");
   }
}

DoublyLinkedList.java

package com.tutorialspoint.list;

public class DoublyLinkedList {

   //this link always point to first Link
   private Link first;
   //this link always point to last Link
   private Link last;

   // create an empty linked list
   public DoublyLinkedList(){
      first = null;
      last = null;
   }

   //is list empty
   public boolean isEmpty(){
      return first == null;
   }

   //insert link at the first location
   public void insertFirst(int key, int data){
      //create a link
      Link link = new Link(key,data);

      if(isEmpty()){
         //make it the last link
         last = link;
      }else {
         //update first prev link
         first.prev = link;
      }

      //point it to old first link
      link.next = first;
      //point first to new first link
      first = link;
   }

   //insert link at the last location
   public void insertLast(int key, int data){
      //create a link
      Link link = new Link(key,data);

      if(isEmpty()){
         //make it the last link
         last = link;
      }else {
         //make link a new last link
         last.next = link;
         //mark old last node as prev of new link
         link.prev = last;
      }

      //point last to new last node
      last = link;
   }

   //delete link at the first location
   public Link deleteFirst(){
      //save reference to first link
      Link tempLink = first;
      //if only one link
      if(first.next == null){
         last = null;
      }else {
         first.next.prev = null;
      }
      first = first.next;
      //return the deleted link
      return tempLink;
   }

   //delete link at the last location
   public Link deleteLast(){
      //save reference to last link
      Link tempLink = last;
      //if only one link
      if(first.next == null){
         first = null;
      }else {
         last.prev.next = null;
      }
      last = last.prev;
      //return the deleted link
      return tempLink;
   }

   //display the list in from first to last
   public void displayForward(){
      //start from the beginning
      Link current = first;
      //navigate till the end of the list
      System.out.print("[ ");
      while(current != null){
         //print data
         current.display();
         //move to next item
         current = current.next;
         System.out.print(" ");
      }
      System.out.print(" ]");
   }

   //display the list from last to first
   public void displayBackward(){
      //start from the last
      Link current = last;
      //navigate till the start of the list
      System.out.print("[ ");
      while(current != null){
         //print data
         current.display();
         //move to next item
         current = current.prev;
         System.out.print(" ");
      }
      System.out.print(" ]");
   }

   //delete a link with given key
   public Link delete(int key){
      //start from the first link
      Link current = first;
      //if list is empty
      if(first == null){
         return null;
      }

      //navigate through list
      while(current.key != key){
      //if it is last node
      if(current.next == null){
            return null;
         }else{
            //move to next link
            current = current.next;
         }
      }

      //found a match, update the link
      if(current == first) {
         //change first to point to next link
            first = current.next;
         }else {
            //bypass the current link
            current.prev.next = current.next;
         }

         if(current == last){
            //change last to point to prev link
            last = current.prev;
         }else {
            current.next.prev = current.prev;
         }
         return current;
      }

   public boolean insertAfter(int key, int newKey, int data){
      //start from the first link
      Link current = first;
      //if list is empty
      if(first == null){
         return false;
      }

      //navigate through list
      while(current.key != key){
         //if it is last node
         if(current.next == null){
            return false;
         }else{
            //move to next link
            current = current.next;
         }
      }

      Link newLink = new Link(newKey,data);
      if(current==last) {
         newLink.next = null;
         last = newLink;
      }
      else {
         newLink.next = current.next;
         current.next.prev = newLink;
      }
      newLink.prev = current;
      current.next = newLink;
      return true;
   }
}

DoublyLinkedListDemo.java

package com.tutorialspoint.list;

public class DoublyLinkedListDemo {
    public static void main(String args[]){
        DoublyLinkedList list = new DoublyLinkedList();

        list.insertFirst(1, 10);
        list.insertFirst(2, 20);
        list.insertFirst(3, 30);

        list.insertLast(4, 1);
        list.insertLast(5, 40);
        list.insertLast(6, 56);

        System.out.print("\nList (First to Last): ");
        list.displayForward();
        System.out.println("");
        System.out.print("\nList (Last to first): ");
        list.displayBackward();

        System.out.print("\nList , after deleting first record: ");
        list.deleteFirst();
        list.displayForward();

        System.out.print("\nList , after deleting last record: ");
        list.deleteLast();
        list.displayForward();

        System.out.print("\nList , insert after key(4) : ");
        list.insertAfter(4,7, 13);
        list.displayForward();

        System.out.print("\nList  , after delete key(4) : ");
        list.delete(4);
        list.displayForward();

    }
}

如果我们编译并运行上述程序,它将生成以下结果 -

List (First to Last): [ {3,30} {2,20} {1,10} {4,1} {5,40} {6,56}  ]

List (Last to first): [ {6,56} {5,40} {4,1} {1,10} {2,20} {3,30}  ]
List (First to Last) after deleting first record: [ {2,20} {1,10} {4,1} {5,40} {6,56}  ]
List  (First to Last) after deleting last record: [ {2,20} {1,10} {4,1} {5,40}  ]
List  (First to Last) insert after key(4) : [ {2,20} {1,10} {4,1} {7,13} {5,40}  ]
List  (First to Last) after delete key(4) : [ {2,20} {1,10} {7,13} {5,40}  ]

DSA using Java - Circular Linked List

Circular Linked List Basics

循环链表是链表的一种变体,其中第一个元素指向最后一个元素,最后一个元素指向第一个元素。单链表和双链表都可以变为循环链表

Singly Linked List as Circular

dsa singly circularlinkedlist

Doubly Linked List as Circular

dsa doubly circularlinkedlist

根据上面显示的说明,以下是需要考虑的重要事项。

  1. 在单链表和双链表两种情况下,最后一个链接的“next”都指向第一个链接。

  2. 在双链表中,第一个链接的“prev”指向最后一个链接。

Basic Operations

循环列表支持以下重要操作。

  1. insert − 在列表的开头插入一个元素。

  2. delete − 从列表的开头插入一个元素。

  3. display − 显示列表。

length Operation

以下代码演示基于单链表的循环链表中的插入操作。

//insert link at the first location
public void insertFirst(int key, int data){
   //create a link
   Link link = new Link(key,data);
   if (isEmpty()) {
      first  = link;
      first.next = first;
   }
   else{
      //point it to old first node
      link.next = first;
      //point first to new first node
      first = link;
   }
}

Deletion Operation

以下代码演示基于单链表的循环链表中的删除操作。

//delete link at the first location
public Link deleteFirst(){
   //save reference to first link
   Link tempLink = first;
   //if only one link
   if(first.next == null){
      last = null;
   }else {
      first.next.prev = null;
   }
   first = first.next;
   //return the deleted link
   return tempLink;
}

Display List Operation

以下代码演示循环链表中的显示列表操作。

public void display(){
   //start from the beginning
   Link current = first;
   //navigate till the end of the list
   System.out.print("[ ");
   if(first != null){
      while(current.next != current){
         //print data
         current.display();
         //move to next item
         current = current.next;
         System.out.print(" ");
      }
   }
   System.out.print(" ]");
}

Demo

Link.java

package com.tutorialspoint.list;

public class CircularLinkedList {
   //this link always point to first Link
   private Link first;

   // create an empty linked list
   public CircularLinkedList(){
      first = null;
   }

   public boolean isEmpty(){
      return first == null;
   }

   public int length(){
      int length = 0;

      //if list is empty
      if(first == null){
         return 0;
      }

      Link current = first.next;

      while(current != first){
         length++;
         current = current.next;
      }
      return length;
   }

   //insert link at the first location
   public void insertFirst(int key, int data){
   //create a link
   Link link = new Link(key,data);
      if (isEmpty()) {
         first  = link;
         first.next = first;
      }
      else{
         //point it to old first node
         link.next = first;
         //point first to new first node
         first = link;
      }
   }

   //delete first item
   public Link deleteFirst(){
      //save reference to first link
      Link tempLink = first;
      if(first.next == first){
         first = null;
         return tempLink;
      }

      //mark next to first link as first
      first = first.next;
      //return the deleted link
      return tempLink;
   }

   public void display(){

      //start from the beginning
      Link current = first;
      //navigate till the end of the list
      System.out.print("[ ");
      if(first != null){
         while(current.next != current){
            //print data
            current.display();
            //move to next item
            current = current.next;
            System.out.print(" ");
         }
      }
      System.out.print(" ]");
   }
}

DoublyLinkedListDemo.java

package com.tutorialspoint.list;

public class CircularLinkedListDemo {
   public static void main(String args[]){
      CircularLinkedList list = new CircularLinkedList();

      list.insertFirst(1, 10);
      list.insertFirst(2, 20);
      list.insertFirst(3, 30);
      list.insertFirst(4, 1);
      list.insertFirst(5, 40);
      list.insertFirst(6, 56);

      System.out.print("\nOriginal List: ");
      list.display();
      System.out.println("");
      while(!list.isEmpty()){
         Link temp = list.deleteFirst();
         System.out.print("Deleted value:");
         temp.display();
         System.out.println("");
      }
      System.out.print("List after deleting all items: ");
      list.display();
      System.out.println("");
   }
}

如果我们编译并运行上述程序,它将生成以下结果 -

Original List: [ {6,56} {5,40} {4,1} {3,30} {2,20}  ]
Deleted value:{6,56}
Deleted value:{5,40}
Deleted value:{4,1}
Deleted value:{3,30}
Deleted value:{2,20}
Deleted value:{1,10}
List after deleting all items: [  ]

DSA using Java - Stack

Overview

堆栈是一种数据结构,它仅允许在某一端对数据执行操作。它只允许访问最后插入的数据。堆栈也被称为 LIFO(后进先出)数据结构,入栈和出栈操作以这样的方式相关联,即只有最后入栈(添加到堆栈)的项目可以出栈(从堆栈中移除)。

Stack Representation

stack

在本文中,我们将使用数组实现堆栈。

Basic Operations

堆栈的以下两个主要操作如下所示。

  1. Push − 将一个元素压入堆栈的顶部。

  2. Pop − 从堆栈的顶部弹出一个元素。

堆栈支持的更多操作如下所示。

  1. Peek − 获取堆栈的顶部元素。

  2. isFull − 检查堆栈是否已满。

  3. isEmpty − 检查堆栈是否为空。

Push Operation

每当一个元素压入堆栈时,堆栈将该元素存储在存储区的顶部并增加顶部索引以备将来使用。如果存储区已满,则通常会显示一条错误消息。

stack push
// push item on the top of the stack
public void push(int data) {

   if(!isFull()){
      // increment top by 1 and insert data
      intArray[++top] = data;
   }else{
      System.out.println("Cannot add data. Stack is full.");
   }
}

Pop Operation

每当一个元素要从堆栈弹出时,堆栈都会从存储区的顶部检索该元素并减少顶部索引以供以后使用。

stack pop
// pop item from the top of the stack
public int pop() {
   // retrieve data and decrement the top by 1
   return intArray[top--];
}

Stack Implementation

Stack.java

package com.tutorialspoint.datastructure;

public class Stack {
   private int size;           // size of the stack
   private int[] intArray;     // stack storage
   private int top;            // top of the stack

   // Constructor
   public Stack(int size){
      this.size = size;
      intArray = new int[size];   //initialize array
      top = -1;                   //stack is initially empty
   }

   // Operation : Push
   // push item on the top of the stack
   public void push(int data) {

      if(!isFull()){
         // increment top by 1 and insert data
         intArray[++top] = data;
      }else{
         System.out.println("Cannot add data. Stack is full.");
      }
   }

   // Operation : Pop
   // pop item from the top of the stack
   public int pop() {
      //retrieve data and decrement the top by 1
      return intArray[top--];
   }

   // Operation : Peek
   // view the data at top of the stack
   public int peek() {
      //retrieve data from the top
      return intArray[top];
   }

   // Operation : isFull
   // return true if stack is full
   public boolean isFull(){
      return (top == size-1);
   }

   // Operation : isEmpty
   // return true if stack is empty
   public boolean isEmpty(){
      return (top == -1);
   }
}

Demo Program

StackDemo.java

package com.tutorialspoint.datastructure;

public class StackDemo {
   public static void main (String[] args){

      // make a new stack
      Stack stack = new Stack(10);

      // push items on to the stack
      stack.push(3);
      stack.push(5);
      stack.push(9);
      stack.push(1);
      stack.push(12);
      stack.push(15);

      System.out.println("Element at top of the stack: " + stack.peek());
      System.out.println("Elements: ");

      // print stack data
      while(!stack.isEmpty()){
         int data = stack.pop();
         System.out.println(data);
      }

      System.out.println("Stack full: " + stack.isFull());
      System.out.println("Stack empty: " + stack.isEmpty());
   }
}

如果我们编译并运行上述程序,它将生成以下结果 -

Element at top of the stack: 15
Elements:
15
12
1
9
5
3
Stack full: false
Stack empty: true

DSA using Java - Parsing Expressions

像 2*(3*4) 这样的普通算术表达式对于人类来说更容易解析,但对于算法来说,解析这种表达式はかなり困难。为了解决这个困难,算法可以使用两步法来解析算术表达式。

  1. 将提供的算术表达式转换为后缀表示。

  2. Evaluate the postfix notation.

.

Infix Notation

普通的算术表达式遵循中缀表示法,其中运算符位于操作数之间。例如,A+B 其中 A 是第一个操作数,B 是第二个操作数,+ 是作用于这两个操作数的运算符。

Postfix Notation

后缀表示法不同于普通算术表达式或中缀表示法,其中运算符位于操作数后面。例如,考虑以下示例:

Sr.No

Infix Notation

Postfix Notation

1

A+B

AB+

2

(A+B)*C

AB+C*

3

A*(B+C)

ABC+*

4

A/B+C/D

AB/CD/+

5

(A+B)*(C+D)

AB+CD+*

6

((A+B)*C)-D

AB+C*D-

Infix to PostFix Conversion

在研究将中缀转换为后缀表示法的方法之前,我们需要考虑中缀表达式求值的基本原理。

  1. 中缀表达式的求值从左到右开始。

  2. 记住优先级,例如 * 的优先级高于 +。 例如

2+3*4 = 2+12.2+3*4 = 14。

  1. 使用括号覆盖优先权,例如

(2+3)*4 = 5*4。(2+3)*4= 20。

现在让我们手动将一个简单の中缀表达式 A+B*C 转换成一个后缀表达式。

Step

Character read

到目前为止解析的中缀表达式

到目前为止开发了后缀表达式

Remarks

1

A

A

A

2

+

A+

A

3

B

A+B

AB

4

*

A+B*

AB

+ 无法复制,因为 * 的优先级更高。

5

C

A+B*C

ABC

6

A+B*C

ABC*

复制 * 因为有两个操作数 B 和 C

7

A+B*C

ABC*+

复制 + 因为有两个操作数 BC 和 A

现在,让我们使用栈将上述中缀表达式 A+B*C 转换为后缀表达式。

Step

Character read

到目前为止解析的中缀表达式

到目前为止开发了后缀表达式

Stack Contents

Remarks

1

A

A

A

2

+

A+

A

+

将 + 运算符压入栈中。

3

B

A+B

AB

+

4

*

A+B*

AB

+*

运算符 * 的优先级高于 。将 * 运算符压入栈中。否则, 会弹出。

5

C

A+B*C

ABC

+*

6

A+B*C

ABC*

+

没有更多的操作数,弹出 * 运算符。

7

A+B*C

ABC*+

Pop the + operator.

现在让我们看另一个示例,通过使用栈将中缀表达式 A*(B+C) 转换为后缀表达式。

Step

Character read

到目前为止解析的中缀表达式

到目前为止开发了后缀表达式

Stack Contents

Remarks

1

A

A

A

2

*

A*

A

*

将 * 运算符压入栈中。

3

(

A*(

A

*(

将 ( 压入栈中。

4

B

A*(B

AB

*(

5

+

A*(B+

AB

*(+

将 + 压入栈中。

6

C

A*(B+C

ABC

*(+

7

)

A*(B+C)

ABC+

*(

Pop the + operator.

8

A*(B+C)

ABC+

*

Pop the ( operator.

9

A*(B+C)

ABC+*

弹出其余运算符。

Demo program

现在,我们将展示使用栈将中缀表达式转换为后缀表达式,然后计算后缀表达式。

package com.tutorialspoint.expression;

public class Stack {

   private int size;
   private int[] intArray;
   private int top;

   //Constructor
   public Stack(int size){
      this.size = size;
      intArray = new int[size];
      top = -1;
   }

   //push item on the top of the stack
   public void push(int data) {
      if(!isFull()){
         //increment top by 1 and insert data
         intArray[++top] = data;
      }else{
         System.out.println("Cannot add data. Stack is full.");
      }
   }

   //pop item from the top of the stack
   public int pop() {
      //retrieve data and decrement the top by 1
      return intArray[top--];
   }

   //view the data at top of the stack
   public int peek() {
      //retrieve data from the top
      return intArray[top];
   }

   //return true if stack is full
   public boolean isFull(){
      return (top == size-1);
   }

   //return true if stack is empty
   public boolean isEmpty(){
      return (top == -1);
   }
}

InfixToPostFix.java

package com.tutorialspoint.expression;

public class InfixToPostfix {
   private Stack stack;
   private String input = "";
   private String output = "";

   public InfixToPostfix(String input){
      this.input = input;
      stack = new Stack(input.length());
   }

   public String translate(){
      for(int i=0;i<input.length();i++){
         char ch = input.charAt(i);
            switch(ch){
               case '+':
               case '-':
                  gotOperator(ch, 1);
                  break;
               case '*':
               case '/':
                  gotOperator(ch, 2);
                  break;
               case '(':
                  stack.push(ch);
                  break;
               case ')':
                  gotParenthesis(ch);
                  break;
               default:
                  output = output+ch;
                  break;
          }
      }

      while(!stack.isEmpty()){
         output = output + (char)stack.pop();
      }

      return output;
   }

      //got operator from input
      public void gotOperator(char operator, int precedence){
      while(!stack.isEmpty()){
         char prevOperator = (char)stack.pop();
         if(prevOperator == '('){
            stack.push(prevOperator);
            break;
         }else{
            int precedence1;
            if(prevOperator == '+' || prevOperator == '-'){
               precedence1 = 1;
            }else{
               precedence1 = 2;
            }

            if(precedence1 < precedence){
               stack.push(Character.getNumericValue(prevOperator));
               break;
            }else{
               output = output + prevOperator;
            }
         }
      }
      stack.push(operator);
   }

   //got operator from input
   public void gotParenthesis(char parenthesis){
      while(!stack.isEmpty()){
         char ch = (char)stack.pop();
         if(ch == '('){
            break;
         }else{
            output = output + ch;
         }
      }
   }
}

PostFixParser.java

package com.tutorialspoint.expression;

public class PostFixParser {
private Stack stack;
private String input;

public PostFixParser(String postfixExpression){
   input = postfixExpression;
   stack = new Stack(input.length());
}

   public int evaluate(){
      char ch;
      int firstOperand;
      int secondOperand;
      int tempResult;

      for(int i=0;i<input.length();i++){
         ch = input.charAt(i);

         if(ch >= '0' && ch <= '9'){
            stack.push(Character.getNumericValue(ch));
         }else{
            firstOperand = stack.pop();
            secondOperand = stack.pop();
            switch(ch){
               case '+':
                  tempResult = firstOperand + secondOperand;
                  break;
               case '-':
                  tempResult = firstOperand - secondOperand;
                  break;
               case '*':
                  tempResult = firstOperand * secondOperand;
                  break;
               case '/':
                  tempResult = firstOperand / secondOperand;
                  break;
               default:
                  tempResult = 0;
            }
            stack.push(tempResult);
         }
      }
      return stack.pop();
   }
}

PostFixDemo.java

package com.tutorialspoint.expression;

public class PostFixDemo {
   public static void main(String args[]){
      String input = "1*(2+3)";
      InfixToPostfix translator = new InfixToPostfix(input);
      String output = translator.translate();
      System.out.println("Infix expression is: " + input);
      System.out.println("Postfix expression is: " + output);

      PostFixParser parser = new PostFixParser(output);
      System.out.println("Result is: " + parser.evaluate());
   }
}

如果我们编译并运行上述程序,它将生成以下结果 -

Infix expression is: 1*(2+3)
Postfix expression is: 123+*
Result is: 5

DSA using Java - Queue

Overview

队列是一种类似于堆栈的数据结构,主要区别在于,插入的第一个项目是要被移除的第一个项目(FIFO - 先进先出),而堆栈是基于 LIFO(后进先出)原理的。

Queue Representation

queue

Basic Operations

  1. insert / enqueue − 向队列后部添加项目。

  2. remove / dequeue − 从队列前部删除项目。

在本文中,我们将使用数组实现队列。队列支持以下更多操作。

  1. Peek − 获取队列前部的元素。

  2. isFull − 检查队列是否已满。

  3. isEmpty − 检查队列是否为空。

Insert / Enqueue Operation

每当将元素插入队列时,队列会增加后索引以供以后使用,并将该元素存储在存储的后端。如果后端到达最后一个索引,并且它被转到最底层。这种安排称为环绕,这种队列是循环队列。此方法也称为入队操作。

queue insert
public void insert(int data){
   if(!isFull()){
      if(rear == MAX-1){
         rear = -1;
      }

      intArray[++rear] = data;
      itemCount++;
   }
}

Remove / Dequeue Operation

每当要从队列中移除一个元素时,队列使用前索引获取该元素并增加前索引。作为环绕设置,如果前索引大于数组的最大索引,则将其设置为 0。

queue remove
public int remove(){
   int data = intArray[front++];
   if(front == MAX){
      front = 0;
   }
   itemCount--;
   return data;
}

Queue Implementation

Queue.java

package com.tutorialspoint.datastructure;

public class Queue {

   private final int MAX;
   private int[] intArray;
   private int front;
   private int rear;
   private int itemCount;

   public Queue(int size){
      MAX = size;
      intArray = new int[MAX];
      front = 0;
      rear = -1;
      itemCount = 0;
   }

   public void insert(int data){
      if(!isFull()){
         if(rear == MAX-1){
            rear = -1;
         }

         intArray[++rear] = data;
         itemCount++;
      }
   }

   public int remove(){
      int data = intArray[front++];
      if(front == MAX){
         front = 0;
      }
      itemCount--;
      return data;
   }

   public int peek(){
      return intArray[front];
   }

   public boolean isEmpty(){
      return itemCount == 0;
   }

   public boolean isFull(){
      return itemCount == MAX;
   }

   public int size(){
      return itemCount;
   }
}

Demo Program

QueueDemo.java

package com.tutorialspoint.datastructure;

public class QueueDemo {
   public static void main(String[] args){
      Queue queue = new Queue(6);

      //insert 5 items
      queue.insert(3);
      queue.insert(5);
      queue.insert(9);
      queue.insert(1);
      queue.insert(12);

      // front : 0
      // rear  : 4
      // ------------------
      // index : 0 1 2 3 4
      // ------------------
      // queue : 3 5 9 1 12

      queue.insert(15);

      // front : 0
      // rear  : 5
      // ---------------------
      // index : 0 1 2 3 4  5
      // ---------------------
      // queue : 3 5 9 1 12 15

      if(queue.isFull()){
         System.out.println("Queue is full!");
      }


      //remove one item
      int num = queue.remove();
      System.out.println("Element removed: "+num);
      // front : 1
      // rear  : 5
      // -------------------
      // index : 1 2 3 4  5
      // -------------------
      // queue : 5 9 1 12 15

      //insert more items
      queue.insert(16);

      // front : 1
      // rear  : -1
      // ----------------------
      // index : 0  1 2 3 4  5
      // ----------------------
      // queue : 16 5 9 1 12 15

      //As queue is full, elements will not be inserted.
      queue.insert(17);
      queue.insert(18);

      // ----------------------
      // index : 0  1 2 3 4  5
      // ----------------------
      // queue : 16 5 9 1 12 15
      System.out.println("Element at front: "+queue.peek());

      System.out.println("----------------------");
      System.out.println("index : 5 4 3 2  1  0");
      System.out.println("----------------------");
      System.out.print("Queue:  ");
      while(!queue.isEmpty()){
         int n = queue.remove();
         System.out.print(n +" ");
      }
   }
}

如果我们编译并运行上述程序,它将生成以下结果 -

Queue is full!
Element removed: 3
Element at front: 5
----------------------
index : 5 4 3 2  1  0
----------------------
Queue:  5 9 1 12 15 16

DSA using Java - Priority Queue

Overview

优先队列是一种比队列更专业的データ结构。与普通队列一样,优先队列具有相同的方法,但有一个主要区别。在优先队列中,项目按键值排序,因此键值最小的项目在前面,键值最大的项目在后面,反之亦然。因此,我们将优先级分配给项目的键值。值越低,优先级越高。以下是优先队列的主要方法。

Basic Operations

  1. insert / enqueue − 向队列后部添加项目。

  2. remove / dequeue − 从队列前部删除项目。

Priority Queue Representation

queue

在本文中,我们将使用数组实现队列。队列支持以下更多操作。

  1. Peek − 获取队列前部的元素。

  2. isFull − 检查队列是否已满。

  3. isEmpty − 检查队列是否为空。

Insert / Enqueue Operation

每当将元素插入队列时,优先队列会根据其顺序插入项目。在此处,我们假设具有高值的具有低优先级。

queue insert
public void insert(int data){
   int i =0;

   if(!isFull()){
      // if queue is empty, insert the data
      if(itemCount == 0){
         intArray[itemCount++] = data;
      }else{
         // start from the right end of the queue
         for(i = itemCount - 1; i >= 0; i-- ){
            // if data is larger, shift existing item to right end
            if(data > intArray[i]){
               intArray[i+1] = intArray[i];
            }else{
               break;
            }
         }
         // insert the data
         intArray[i+1] = data;
         itemCount++;
      }
   }
}

Remove / Dequeue Operation

每当要从队列中移除一个元素时,队列使用项目计数获取元素。一旦移除元素。项目计数减少一。

queue remove
public int remove(){
    return intArray[--itemCount];
}

Priority Queue Implementation

PriorityQueue.java

package com.tutorialspoint.datastructure;

public class PriorityQueue {
   private final int MAX;
   private int[] intArray;
   private int itemCount;

   public PriorityQueue(int size){
      MAX = size;
      intArray = new int[MAX];
      itemCount = 0;
   }

   public void insert(int data){
      int i =0;

      if(!isFull()){
         // if queue is empty, insert the data
         if(itemCount == 0){
            intArray[itemCount++] = data;
         }else{
            // start from the right end of the queue
            for(i = itemCount - 1; i >= 0; i-- ){
               // if data is larger, shift existing item to right end
               if(data > intArray[i]){
                  intArray[i+1] = intArray[i];
               }else{
                  break;
               }
            }
            // insert the data
            intArray[i+1] = data;
            itemCount++;
         }
      }
   }

   public int remove(){
      return intArray[--itemCount];
   }

   public int peek(){
      return intArray[itemCount - 1];
   }

   public boolean isEmpty(){
      return itemCount == 0;
   }

   public boolean isFull(){
      return itemCount == MAX;
   }

   public int size(){
      return itemCount;
   }
}

Demo Program

PriorityQueueDemo.java

package com.tutorialspoint.datastructure;

public class PriorityQueueDemo {
   public static void main(String[] args){
      PriorityQueue queue = new PriorityQueue(6);

      //insert 5 items
      queue.insert(3);
      queue.insert(5);
      queue.insert(9);
      queue.insert(1);
      queue.insert(12);

      // ------------------
      // index : 0  1 2 3 4
      // ------------------
      // queue : 12 9 5 3 1

      queue.insert(15);

      // ---------------------
      // index : 0  1 2 3 4  5
      // ---------------------
      // queue : 15 12 9 5 3 1

      if(queue.isFull()){
         System.out.println("Queue is full!");
      }


      //remove one item
      int num = queue.remove();
      System.out.println("Element removed: "+num);
      // ---------------------
      // index : 0  1  2 3 4
      // ---------------------
      // queue : 15 12 9 5 3

      //insert more items
      queue.insert(16);

      // ----------------------
      // index :  0  1 2 3 4  5
      // ----------------------
      // queue : 16 15 12 9 5 3

      //As queue is full, elements will not be inserted.
      queue.insert(17);
      queue.insert(18);

      // ----------------------
      // index : 0   1  2 3 4 5
      // ----------------------
      // queue : 16 15 12 9 5 3
      System.out.println("Element at front: "+queue.peek());
      System.out.println("----------------------");
      System.out.println("index : 5 4 3 2  1  0");
      System.out.println("----------------------");
      System.out.print("Queue:  ");
      while(!queue.isEmpty()){
         int n = queue.remove();
         System.out.print(n +" ");
      }
   }
}

如果我们编译并运行上述程序,它将生成以下结果 -

Queue is full!
Element removed: 1
Element at front: 3
----------------------
index : 5 4 3 2  1  0
----------------------
Queue:  3 5 9 12 15 16

DSA using Java - Tree

Overview

树表示通过边连接起来的多个节点。我们将专门讨论二叉树或二叉搜索树。

二叉树是一个特殊的数据结构,用于数据存储。二叉树有一个特殊条件,即每个节点最多可以有两个子节点。二叉树同时具有有序数组和链表的优点,如搜索像在已排序数组中一样快速,插入或删除操作像在链表中一样快。

Terms

以下是关于树的一些重要术语。

  1. Path − 路径是指沿着树边缘的一系列节点。

  2. Root − 树顶部的节点称为根节点。每个树只有一个根节点,并且从根节点到任何节点只有一条路径。

  3. Parent − 除了根节点之外的任何节点都有一条向上的边连接到一个称为父节点的节点。

  4. Child − 通过向下的边与给定节点相连接的下方节点称为其子节点。

  5. Leaf − 没有子节点的节点称为叶节点。

  6. Subtree − 子树表示节点的后代。

  7. Visiting − 访问是指在控制权在节点上的时候检查节点的值。

  8. Traversing − 遍历指按照特定顺序经过节点。

  9. Levels − 节点的等级表示节点的代。如果根节点在第 0 级,那么它的下一个子节点在第 1 级,它的孙子节点在第 2 级,以此类推。

  10. keys − 键表示节点的值,基于此值针对节点执行搜索操作。

二叉搜索树表现出一种特殊的行为。节点的左子节点的值必须小于其父节点的值,节点的右子节点的值必须大于其父节点的值。

Binary Search Tree Representation

我们将使用节点对象实现树,并通过引用将它们连接起来。

Basic Operations

下面是一些树的基本基本操作。

  1. Search − 在树中搜索一个元素。

  2. Insert − 在树中插入一个元素。

  3. Preorder Traversal - 以先序方式遍历树。

  4. Inorder Traversal - 以中序方式遍历树。

  5. Postorder Traversal - 以后序方式遍历树。

Node

定义一个节点,它具有一些数据、针对其左侧和右侧子节点的引用。

public class Node {
   public int data;
   public Node leftChild;
   public Node rightChild;

   public Node(){}

   public void display(){
      System.out.print("("+data+ ")");
   }
}

Search Operation

如果某一元素搜索。从根节点开始搜索,此时,如果数据小于键值,在左子树中搜索元素,否则,在右子树中搜索元素。遵循相同的算法针对每个节点。

public Node search(int data){
   Node current = root;
   System.out.print("Visiting elements: ");
   while(current.data != data){
      if(current != null)
         System.out.print(current.data + " ");
         //go to left tree
         if(current.data > data){
            current = current.leftChild;
         }//else go to right tree
         else{
            current = current.rightChild;
         }
         //not found
         if(current == null){
            return null;
         }
      }
   return current;
}

Insert Operation

如果某一元素要插入。首先,找到它适当的位置。从根节点开始搜索,此时,如果数据小于键值,在左子树中查找空位置,并插入数据。否则,在右子树中查找空位置,并插入数据。

public void insert(int data){
   Node tempNode = new Node();
   tempNode.data = data;

   //if tree is empty
   if(root == null){
      root = tempNode;
   }else{
      Node current = root;
      Node parent = null;

      while(true){
         parent = current;
         //go to left of the tree
         if(data < parent.data){
            current = current.leftChild;
            //insert to the left
            if(current == null){
               parent.leftChild = tempNode;
               return;
            }
         }//go to right of the tree
         else{
            current = current.rightChild;
            //insert to the right
            if(current == null){
               parent.rightChild = tempNode;
               return;
            }
         }
      }
   }
}

Preorder Traversal

这是一个简单的三步流程。

  1. visit root node

  2. traverse left subtree

  3. traverse right subtree

private void preOrder(Node root){
   if(root!=null){
      System.out.print(root.data + " ");
      preOrder(root.leftChild);
      preOrder(root.rightChild);
   }
}

Inorder Traversal

这是一个简单的三步流程。

  1. traverse left subtree

  2. visit root node

  3. traverse right subtree

private void inOrder(Node root){
   if(root!=null){
      inOrder(root.leftChild);
      System.out.print(root.data + " ");
      inOrder(root.rightChild);
   }
}

Postorder Traversal

这是一个简单的三步流程。

  1. traverse left subtree

  2. traverse right subtree

  3. visit root node

private void postOrder(Node root){
   if(root!=null){
      postOrder(root.leftChild);
      postOrder(root.rightChild);
      System.out.print(root.data + " ");
   }
}

Tree Implementation

Node.java

package com.tutorialspoint.datastructure;

public class Node {
   public int data;
   public Node leftChild;
   public Node rightChild;

   public Node(){}

   public void display(){
      System.out.print("("+data+ ")");
   }
}

Tree.java

package com.tutorialspoint.datastructure;

public class Tree {
   private Node root;

   public Tree(){
      root = null;
   }

   public Node search(int data){
      Node current = root;
      System.out.print("Visiting elements: ");
      while(current.data != data){
         if(current != null)
            System.out.print(current.data + " ");
            //go to left tree
            if(current.data > data){
               current = current.leftChild;
            }//else go to right tree
            else{
               current = current.rightChild;
            }
            //not found
            if(current == null){
               return null;
            }
         }
      return current;
   }

   public void insert(int data){
      Node tempNode = new Node();
      tempNode.data = data;

      //if tree is empty
      if(root == null){
         root = tempNode;
     }else{
         Node current = root;
         Node parent = null;

         while(true){
            parent = current;
            //go to left of the tree
            if(data < parent.data){
               current = current.leftChild;
               //insert to the left
               if(current == null){
                  parent.leftChild = tempNode;
                  return;
               }
            }//go to right of the tree
            else{
               current = current.rightChild;
               //insert to the right
               if(current == null){
                  parent.rightChild = tempNode;
                  return;
               }
            }
         }
      }
   }

   public void traverse(int traversalType){
      switch(traversalType){
         case 1:
            System.out.print("\nPreorder traversal: ");
            preOrder(root);
            break;
         case 2:
            System.out.print("\nInorder traversal: ");
            inOrder(root);
            break;
         case 3:
            System.out.print("\nPostorder traversal: ");
            postOrder(root);
            break;
         }
   }

   private void preOrder(Node root){
      if(root!=null){
         System.out.print(root.data + " ");
         preOrder(root.leftChild);
         preOrder(root.rightChild);
      }
   }

   private void inOrder(Node root){
      if(root!=null){
         inOrder(root.leftChild);
         System.out.print(root.data + " ");
         inOrder(root.rightChild);
      }
   }

   private void postOrder(Node root){
      if(root!=null){
         postOrder(root.leftChild);
         postOrder(root.rightChild);
         System.out.print(root.data + " ");
      }
   }
}

Demo Program

TreeDemo.java

package com.tutorialspoint.datastructure;

public class TreeDemo {
   public static void main(String[] args){
      Tree tree = new Tree();

      /*                     11               //Level 0
      */
      tree.insert(11);
      /*                     11               //Level 0
      *                      |
      *                      |---20           //Level 1
      */
      tree.insert(20);
      /*                     11               //Level 0
      *                      |
      *                  3---|---20           //Level 1
      */
      tree.insert(3);
      /*                     11               //Level 0
      *                      |
      *                  3---|---20           //Level 1
      *                           |
      *                           |--42       //Level 2
      */
      tree.insert(42);
      /*                     11               //Level 0
      *                      |
      *                  3---|---20           //Level 1
      *                           |
      *                           |--42       //Level 2
      *                               |
      *                               |--54   //Level 3
      */
      tree.insert(54);
      /*                     11               //Level 0
      *                      |
      *                  3---|---20           //Level 1
      *                           |
      *                       16--|--42       //Level 2
      *                               |
      *                               |--54   //Level 3
      */
      tree.insert(16);
      /*                     11               //Level 0
      *                      |
      *                  3---|---20           //Level 1
      *                           |
      *                       16--|--42       //Level 2
      *                               |
      *                           32--|--54   //Level 3
      */
      tree.insert(32);
      /*                     11               //Level 0
      *                      |
      *                  3---|---20           //Level 1
      *                  |        |
      *                  |--9 16--|--42       //Level 2
      *                               |
      *                           32--|--54   //Level 3
      */
      tree.insert(9);
      /*                     11               //Level 0
      *                      |
      *                  3---|---20           //Level 1
      *                  |        |
      *                  |--9 16--|--42       //Level 2
      *                     |         |
      *                  4--|     32--|--54   //Level 3
      */
      tree.insert(4);
      /*                     11               //Level 0
      *                      |
      *                  3---|---20           //Level 1
      *                  |        |
      *                  |--9 16--|--42       //Level 2
      *                     |         |
      *                  4--|--10 32--|--54   //Level 3
      */
      tree.insert(10);
      Node node = tree.search(32);
      if(node!=null){
         System.out.print("Element found.");
         node.display();
         System.out.println();
      }else{
         System.out.println("Element not found.");
      }

      Node node1 = tree.search(2);
      if(node1!=null){
         System.out.println("Element found.");
         node1.display();
         System.out.println();
      }else{
         System.out.println("Element not found.");
      }

      //pre-order traversal
      //root, left ,right
      tree.traverse(1);
      //in-order traversal
      //left, root ,right
      tree.traverse(2);
      //post order traversal
      //left, right, root
      tree.traverse(3);
   }
}

如果我们编译并运行上述程序,它将生成以下结果 -

Visiting elements: 11 20 42 Element found.(32)
Visiting elements: 11 3 Element not found.

Preorder traversal: 11 3 9 4 10 20 16 42 32 54
Inorder traversal: 3 4 9 10 11 16 20 32 42 54
Postorder traversal: 4 10 9 3 16 32 54 42 20 11

DSA using Java - Hash Table

Overview

哈希表是一种数据结构,其中插入和搜索操作非常快,与哈希表的大小无关。它几乎是常量或 O(1)。哈希表使用数组作为存储介质,并使用哈希技术来生成元素被插入或被定位到的索引。

Hashing

哈希是一种将一系列键值转换为一系列数组索引的技术。我们将使用模运算符来获得一系列键值。考虑一个大小为 20 的哈希表示例,以下项目需要存储。项目采用 (key,value) 格式。

  1. (1,20)

  2. (2,70)

  3. (42,80)

  4. (4,25)

  5. (12,44)

  6. (14,32)

  7. (17,11)

  8. (13,78)

  9. (37,98)

Sr.No.

Key

Hash

Array Index

1

1

1 % 20 = 1

1

2

2

2 % 20 = 2

2

3

42

42 % 20 = 2

2

4

4

4 % 20 = 4

4

5

12

12 % 20 = 12

12

6

14

14 % 20 = 14

14

7

17

17 % 20 = 17

17

8

13

13 % 20 = 13

13

9

37

37 % 20 = 17

17

Linear Probing

我们可以看到,可能发生使用哈希技术创建的索引已经是数组的已用索引。在这种情况下,我们可以通过查看下一个单元格来搜索数组中的下一个空闲位置,直到我们找到一个空闲单元格。这种技术称为线性探查。

Sr.No.

Key

Hash

Array Index

在线性探查之后,数组索引

1

1

1 % 20 = 1

1

1

2

2

2 % 20 = 2

2

2

3

42

42 % 20 = 2

2

3

4

4

4 % 20 = 4

4

4

5

12

12 % 20 = 12

12

12

6

14

14 % 20 = 14

14

14

7

17

17 % 20 = 17

17

17

8

13

13 % 20 = 13

13

13

9

37

37 % 20 = 17

17

18

Basic Operations

以下是哈希表的基本主要操作。

  1. Search − 在哈希表中搜索元素。

  2. Insert − 在哈希表中插入元素。

  3. delete − 从哈希表中删除元素。

DataItem

定义一个具有某些数据和键的数据项,根据该键在哈希表中进行搜索。

public class DataItem {
   private int key;
   private int data;

   public DataItem(int key, int data){
      this.key = key;
      this.data = data;
   }

   public int getKey(){
      return key;
   }

   public int getData(){
      return data;
   }
}

Hash Method

定义一种哈希方法,用于计算数据项键的哈希代码。

public int hashCode(int key){
   return key % size;
}

Search Operation

每当要搜索元素时。计算已传递键的哈希代码,并使用该哈希代码作为数组中的索引来定位该元素。如果在计算的哈希代码中没有找到元素,请使用线性探测获得元素。

public DataItem search(int key){
   //get the hash
   int hashIndex = hashCode(key);
   //move in array until an empty
   while(hashArray[hashIndex] !=null){
      if(hashArray[hashIndex].getKey() == key)
         return hashArray[hashIndex];
      //go to next cell
      ++hashIndex;
      //wrap around the table
      hashIndex %= size;
   }
   return null;
}

Insert Operation

每当要插入元素时。计算已传递键的哈希代码,并使用该哈希代码作为数组中的索引来定位该索引。如果在计算的哈希代码中找到了某个元素,请对空位置使用线性探测。

public void insert(DataItem item){
   int key = item.getKey();

   //get the hash
   int hashIndex = hashCode(key);

   //move in array until an empty or deleted cell
   while(hashArray[hashIndex] !=null
      && hashArray[hashIndex].getKey() != -1){
      //go to next cell
      ++hashIndex;
      //wrap around the table
      hashIndex %= size;
   }

   hashArray[hashIndex] = item;
}

Delete Operation

每当要删除元素时。计算已传递键的哈希代码,并使用该哈希代码作为数组中的索引来定位该索引。如果在计算的哈希代码中找不到元素,请使用线性探测获得元素。找到后,在那里存储一个虚拟项来保持哈希表的完整性能。

public DataItem delete(DataItem item){
   int key = item.getKey();

   //get the hash
   int hashIndex = hashCode(key);

   //move in array until an empty
   while(hashArray[hashIndex] !=null){
      if(hashArray[hashIndex].getKey() == key){
         DataItem temp = hashArray[hashIndex];
         //assign a dummy item at deleted position
         hashArray[hashIndex] = dummyItem;
         return temp;
      }
      //go to next cell
      ++hashIndex;
      //wrap around the table
      hashIndex %= size;
   }
   return null;
}

HashTable Implementation

DataItem.java

package com.tutorialspoint.datastructure;

public class DataItem {
   private int key;
   private int data;

   public DataItem(int key, int data){
      this.key = key;
      this.data = data;
   }

   public int getKey(){
      return key;
   }

   public int getData(){
      return data;
   }
}

HashTable.java

package com.tutorialspoint.datastructure;

public class HashTable {

   private DataItem[] hashArray;
   private int size;
   private DataItem dummyItem;

   public HashTable(int size){
      this.size = size;
      hashArray = new DataItem[size];
      dummyItem = new DataItem(-1,-1);
   }

   public void display(){
      for(int i=0; i<size; i++) {
         if(hashArray[i] != null)
            System.out.print(" ("
               +hashArray[i].getKey()+","
               +hashArray[i].getData() + ") ");
         else
            System.out.print(" ~~ ");
      }
      System.out.println("");
   }

   public int hashCode(int key){
      return key % size;
   }

   public DataItem search(int key){
      //get the hash
      int hashIndex = hashCode(key);
      //move in array until an empty
      while(hashArray[hashIndex] !=null){
         if(hashArray[hashIndex].getKey() == key)
            return hashArray[hashIndex];
         //go to next cell
         ++hashIndex;
         //wrap around the table
         hashIndex %= size;
      }
      return null;
   }

   public void insert(DataItem item){
      int key = item.getKey();

      //get the hash
      int hashIndex = hashCode(key);

      //move in array until an empty or deleted cell
      while(hashArray[hashIndex] !=null
         && hashArray[hashIndex].getKey() != -1){
         //go to next cell
         ++hashIndex;
         //wrap around the table
         hashIndex %= size;
      }

      hashArray[hashIndex] = item;
   }

   public DataItem delete(DataItem item){
      int key = item.getKey();

      //get the hash
      int hashIndex = hashCode(key);

      //move in array until an empty
      while(hashArray[hashIndex] !=null){
         if(hashArray[hashIndex].getKey() == key){
            DataItem temp = hashArray[hashIndex];
            //assign a dummy item at deleted position
            hashArray[hashIndex] = dummyItem;
            return temp;
         }
         //go to next cell
         ++hashIndex;
         //wrap around the table
         hashIndex %= size;
      }
      return null;
   }
}

Demo Program

HashTableDemo.java

package com.tutorialspoint.datastructure;

public class HashTableDemo {
   public static void main(String[] args){
      HashTable hashTable = new HashTable(20);

      hashTable.insert(new DataItem(1, 20));
      hashTable.insert(new DataItem(2, 70));
      hashTable.insert(new DataItem(42, 80));
      hashTable.insert(new DataItem(4, 25));
      hashTable.insert(new DataItem(12, 44));
      hashTable.insert(new DataItem(14, 32));
      hashTable.insert(new DataItem(17, 11));
      hashTable.insert(new DataItem(13, 78));
      hashTable.insert(new DataItem(37, 97));

      hashTable.display();

      DataItem item = hashTable.search(37);

      if(item != null){
         System.out.println("Element found: "+ item.getData());
      }else{
         System.out.println("Element not found");
      }

      hashTable.delete(item);

      item = hashTable.search(37);

      if(item != null){
         System.out.println("Element found: "+ item.getData());
      }else{
         System.out.println("Element not found");
      }
   }
}

如果我们编译并运行上述程序,它将生成以下结果 -

 ~~  (1,20)  (2,70)  (42,80)  (4,25)  ~~  ~~  ~~  ~~  ~~  ~~  ~~ (12,44)  (13,78)  (14,32)  ~~  ~~  (17,11)  (37,97)  ~~
Element found: 97
Element not found

DSA using Java - Heap

Overview

堆表示一种特殊基于树的数据结构,用于表示优先级队列或堆排序。我们具体来讨论二叉堆树。

二叉堆树可以分类为具有两个约束的二叉树 −

  1. Completeness − 二叉堆树是一个完全二叉树,除了最后一层可能没有所有元素,但从左到右的元素应该填充。

  2. Heapness − 所有父节点都应该大于或小于它们的子节点。如果父节点大于其子节点,则称为最大堆,否则称为最小堆。最大堆用于堆排序,而最小堆用于优先级队列。我们正在考虑最小堆,并将使用数组实现相同的最小堆。

Basic Operations

以下是最小堆的基本主要操作,如下。

  1. Insert − 在堆中插入一个元素。

  2. Get Minimum − 从堆中获取最小元素。

  3. Remove Minimum − 从堆中删除最小元素

Insert Operation

  1. 每当要插入一个元素时。在数组末尾插入元素。将堆的尺寸增加 1。

堆化元素,同时堆属性被破坏。比较元素与父值,并在需要时交换它们。
public void insert(int value) {
   size++;
   intArray[size - 1] = value;
   heapUp(size - 1);
}

private void heapUp(int nodeIndex){
   int parentIndex, tmp;
   if (nodeIndex != 0) {
      parentIndex = getParentIndex(nodeIndex);
      if (intArray[parentIndex] > intArray[nodeIndex]) {
         tmp = intArray[parentIndex];
         intArray[parentIndex] = intArray[nodeIndex];
         intArray[nodeIndex] = tmp;
         heapUp(parentIndex);
      }
   }
}

Get Minimum

获取实现堆的数组的第一个元素作为根。

public int getMinimum(){
   return intArray[0];
}

Remove Minimum

  1. 每当要删除一个元素时。获取数组的最后一个元素,并减少堆的尺寸 1。

堆化元素,同时堆属性被破坏。比较元素与子值,并在需要时交换它们。
public void removeMin() {
   intArray[0] = intArray[size - 1];
   size--;
   if (size > 0)
      heapDown(0);
}

private void heapDown(int nodeIndex){
   int leftChildIndex, rightChildIndex, minIndex, tmp;
   leftChildIndex = getLeftChildIndex(nodeIndex);
   rightChildIndex = getRightChildIndex(nodeIndex);
   if (rightChildIndex >= size) {
      if (leftChildIndex >= size)
         return;
      else
         minIndex = leftChildIndex;
   } else {
      if (intArray[leftChildIndex] <= intArray[rightChildIndex])
         minIndex = leftChildIndex;
      else
         minIndex = rightChildIndex;
   }
   if (intArray[nodeIndex] > intArray[minIndex]) {
      tmp = intArray[minIndex];
      intArray[minIndex] = intArray[nodeIndex];
      intArray[nodeIndex] = tmp;
      heapDown(minIndex);
   }
}

Heap Implementation

Heap.java

package com.tutorialspoint.datastructure;

public class Heap {
   private int[] intArray;
   private int size;

   public Heap(int size){
      intArray = new int[size];
   }

   public boolean isEmpty(){
      return size == 0;
   }

   public int getMinimum(){
      return intArray[0];
   }

   public int getLeftChildIndex(int nodeIndex){
      return 2*nodeIndex +1;
   }

   public int getRightChildIndex(int nodeIndex){
      return 2*nodeIndex +2;
   }

   public int getParentIndex(int nodeIndex){
      return (nodeIndex -1)/2;
   }

   public boolean isFull(){
      return size == intArray.length;
   }

   public void insert(int value) {
      size++;
      intArray[size - 1] = value;
      heapUp(size - 1);
   }

   public void removeMin() {
      intArray[0] = intArray[size - 1];
      size--;
      if (size > 0)
         heapDown(0);
   }

   /**
   * Heap up the new element,until heap property is broken.
   * Steps:
   * 1. Compare node's value with parent's value.
   * 2. Swap them, If they are in wrong order.
   * */
   private void heapUp(int nodeIndex){
      int parentIndex, tmp;
      if (nodeIndex != 0) {
         parentIndex = getParentIndex(nodeIndex);
         if (intArray[parentIndex] > intArray[nodeIndex]) {
            tmp = intArray[parentIndex];
            intArray[parentIndex] = intArray[nodeIndex];
            intArray[nodeIndex] = tmp;
            heapUp(parentIndex);
         }
      }
   }

   /**
   * Heap down the root element being least in value,until heap property is broken.
   * Steps:
   * 1.If current node has no children, done.
   * 2.If current node has one children and heap property is broken,
   * 3.Swap the current node and child node and heap down.
   * 4.If current node has one children and heap property is broken, find smaller one
   * 5.Swap the current node and child node and heap down.
   * */
   private void heapDown(int nodeIndex){
      int leftChildIndex, rightChildIndex, minIndex, tmp;
      leftChildIndex = getLeftChildIndex(nodeIndex);
      rightChildIndex = getRightChildIndex(nodeIndex);
      if (rightChildIndex >= size) {
         if (leftChildIndex >= size)
            return;
         else
            minIndex = leftChildIndex;
      } else {
         if (intArray[leftChildIndex] <= intArray[rightChildIndex])
            minIndex = leftChildIndex;
         else
            minIndex = rightChildIndex;
      }
      if (intArray[nodeIndex] > intArray[minIndex]) {
         tmp = intArray[minIndex];
         intArray[minIndex] = intArray[nodeIndex];
         intArray[nodeIndex] = tmp;
         heapDown(minIndex);
      }
   }
}

Demo Program

HeapDemo.java

package com.tutorialspoint.datastructure;

public class HeapDemo {
   public static void main(String[] args){
      Heap heap = new Heap(10);
       /*                     5                //Level 0
        *
        */
      heap.insert(5);
       /*                     1                //Level 0
        *                     |
        *                 5---|                //Level 1
        */
      heap.insert(1);
       /*                     1                //Level 0
        *                     |
        *                 5---|---3            //Level 1
        */
      heap.insert(3);
       /*                     1                //Level 0
        *                     |
        *                 5---|---3            //Level 1
        *                 |
        *              8--|                    //Level 2
        */
      heap.insert(8);
      /*                     1                //Level 0
       *                     |
       *                 5---|---3            //Level 1
       *                 |
       *              8--|--9                 //Level 2
       */
      heap.insert(9);
      /*                     1                 //Level 0
       *                     |
       *                 5---|---3             //Level 1
       *                 |       |
       *              8--|--9 6--|             //Level 2
       */
      heap.insert(6);
      /*                     1                 //Level 0
       *                     |
       *                 5---|---2             //Level 1
       *                 |       |
       *              8--|--9 6--|--3          //Level 2
       */
      heap.insert(2);

      System.out.println(heap.getMinimum());

      heap.removeMin();
      /*                     2                 //Level 0
       *                     |
       *                 5---|---3             //Level 1
       *                 |       |
       *              8--|--9 6--|             //Level 2
       */
      System.out.println(heap.getMinimum());
   }
}

如果我们编译并运行上述程序,它将生成以下结果 -

1
2

DSA using Java - Graph

Overview

图形是一种用于对数学图形进行建模的数据结构。它包含一组连接的成对内容,称为顶点的边。我们可以使用顶点数组和边进行的二维数组来表示图形。

重要术语

  1. Vertex - 图形中的各个节点表示为顶点。在下方的范例中,标记的圆圈代表顶点。A 至 G 即顶点。我们可以使用数组来表达它们,如下图所示。此处可以通过索引 0 识别 A。可以通过 1 等识别 B,依此类推。

  2. Edge - 边表示两个顶点之间的路径或者两个顶点之间的线。在下方的范例中,从 A 到 B、从 B 到 C 等线表示边。我们可以使用二维数组来表示数组,如下图所示。此处 AB 可以表示为 0 行、1 列中的 1,BC 可以表示为 1 行、2 列中的 1,依此类推,其他组合保持为 0。

  3. Adjacency - 两个节点或顶点通过边互相连接,则它们是相邻的。在下方的范例中,B 邻近 A,C 邻近 B,依此类推。

  4. Path - 路径表示两个顶点之间的边序列。在下方的范例中,ABCD 表示从 A 到 D 的路径。

Basic Operations

以下是图形的基本主操作。

  1. Add Vertex - 向图形添加一个顶点。

  2. Add Edge - 在图形的两个顶点之间添加一条边。

  3. Display Vertex − 显示图的一个顶点。

Add Vertex Operation

//add vertex to the array of vertex
public void addVertex(char label){
   lstVertices[vertexCount++] = new Vertex(label);
}

Add Edge Operation

//add edge to edge array
public void addEdge(int start,int end){
   adjMatrix[start][end] = 1;
   adjMatrix[end][start] = 1;
}

Display Edge Operation

//display the vertex
public void displayVertex(int vertexIndex){
   System.out.print(lstVertices[vertexIndex].label+" ");
}

Traversal Algorithms

以下是图上的重要遍历算法。

  1. Depth First Search − 以深度方向遍历图。

  2. Breadth First Search − 以广度方向遍历图。

Depth First Search Algorithm

深度优先搜索算法 (DFS) 以深度方向遍历图并使用一个堆栈记住在任何迭代中发生死锁时获取下一个顶点以开始搜索。

如上例所示,DFS 算法首先从 A 到 B 到 C 到 D,然后到 E,再到 F,最后到 G。它采用以下规则。

  1. Rule 1 − 访问相邻的未访问过的顶点。将其标记为已访问。显示它。将其压入堆栈。

  2. Rule 2 − 如果找不到相邻顶点,则从堆栈弹出一个顶点。(它会从堆栈中弹出所有没有相邻顶点的顶点。)

  3. Rule 3 − 重复规则 1 和规则 2,直到堆栈为空。

public void depthFirstSearch(){
   //mark first node as visited
   lstVertices[0].visited = true;
   //display the vertex
   displayVertex(0);
   //push vertex index in stack
   stack.push(0);

   while(!stack.isEmpty()){
      //get the unvisited vertex of vertex which is at top of the stack
      int unvisitedVertex = getAdjUnvisitedVertex(stack.peek());
      //no adjacent vertex found
      if(unvisitedVertex == -1){
         stack.pop();
      }else{
         lstVertices[unvisitedVertex].visited = true;
         displayVertex(unvisitedVertex);
         stack.push(unvisitedVertex);
      }
   }

   //stack is empty, search is complete, reset the visited flag
   for(int i=0;i<vertexCount;i++){
      lstVertices[i].visited = false;
   }
}

Breadth First Search Algorithm

广度优先搜索算法 (BFS) 以广度方向遍历图并使用一个队列记住在任何迭代中发生死锁时获取下一个顶点以开始搜索。

如上例所示,BFS 算法首先从 A 到 B 到 E 到 F,然后到 C 和 G,最后到 D。它采用以下规则。

  1. Rule 1 − 访问相邻的未访问过的顶点。将其标记为已访问。显示它。将其插入队列。

  2. Rule 2 − 如果找不到相邻顶点,则从队列中移除第一个顶点。

  3. Rule 3 − 重复规则 1 和规则 2,直到队列为空。

public void breadthFirstSearch(){
   //mark first node as visited
   lstVertices[0].visited = true;
   //display the vertex
   displayVertex(0);
   //insert vertex index in queue
   queue.insert(0);

   int unvisitedVertex;
   while(!queue.isEmpty()){
      //get the unvisited vertex of vertex which is at front of the queue
      int tempVertex = queue.remove();
      //no adjacent vertex found
      while((unvisitedVertex=getAdjUnvisitedVertex(tempVertex)) != -1){
         lstVertices[unvisitedVertex].visited = true;
         displayVertex(unvisitedVertex);
         queue.insert(unvisitedVertex);
      }
   }

   //queue is empty, search is complete, reset the visited flag
   for(int i=0;i<vertexCount;i++){
      lstVertices[i].visited = false;
   }
}

Graph Implementation

Stack.java

package com.tutorialspoint.datastructure;

public class Stack {
   private int size;           // size of the stack
   private int[] intArray;     // stack storage
   private int top;            // top of the stack

   // Constructor
   public Stack(int size){
      this.size = size;
      intArray = new int[size];   //initialize array
      top = -1;                   //stack is initially empty
   }

   // Operation : Push
   // push item on the top of the stack
   public void push(int data) {

      if(!isFull()){
         // increment top by 1 and insert data
         intArray[++top] = data;
      }else{
         System.out.println("Cannot add data. Stack is full.");
      }
   }

   // Operation : Pop
   // pop item from the top of the stack
   public int pop() {
      //retrieve data and decrement the top by 1
      return intArray[top--];
   }

   // Operation : Peek
   // view the data at top of the stack
   public int peek() {
      //retrieve data from the top
      return intArray[top];
   }

   // Operation : isFull
   // return true if stack is full
   public boolean isFull(){
      return (top == size-1);
   }

   // Operation : isEmpty
   // return true if stack is empty
   public boolean isEmpty(){
      return (top == -1);
   }
}

Queue.java

package com.tutorialspoint.datastructure;

public class Queue {

   private final int MAX;
   private int[] intArray;
   private int front;
   private int rear;
   private int itemCount;

   public Queue(int size){
      MAX = size;
      intArray = new int[MAX];
      front = 0;
      rear = -1;
      itemCount = 0;
   }

   public void insert(int data){
      if(!isFull()){
         if(rear == MAX-1){
            rear = -1;
         }

         intArray[++rear] = data;
         itemCount++;
      }
   }

   public int remove(){
      int data = intArray[front++];
      if(front == MAX){
         front = 0;
      }
      itemCount--;
      return data;
   }

   public int peek(){
      return intArray[front];
   }

   public boolean isEmpty(){
      return itemCount == 0;
   }

   public boolean isFull(){
      return itemCount == MAX;
   }

   public int size(){
      return itemCount;
   }
}

Vertex.java

package com.tutorialspoint.datastructure;

public class Vertex {
   public char label;
   public boolean visited;

   public Vertex(char label){
      this.label = label;
      visited = false;
   }
}

Graph.java

package com.tutorialspoint.datastructure;

public class Graph {
   private final int MAX = 20;
   //array of vertices
   private Vertex lstVertices[];
   //adjacency matrix
   private int adjMatrix[][];
   //vertex count
   private int vertexCount;

   private Stack stack;
   private Queue queue;

   public Graph(){
      lstVertices = new Vertex[MAX];
      adjMatrix = new int[MAX][MAX];
      vertexCount = 0;
      stack = new Stack(MAX);
      queue = new Queue(MAX);
      for(int j=0; j<MAX; j++) // set adjacency
         for(int k=0; k<MAX; k++) // matrix to 0
            adjMatrix[j][k] = 0;
   }

   //add vertex to the vertex list
   public void addVertex(char label){
      lstVertices[vertexCount++] = new Vertex(label);
   }

   //add edge to edge array
   public void addEdge(int start,int end){
      adjMatrix[start][end] = 1;
      adjMatrix[end][start] = 1;
   }

   //display the vertex
   public void displayVertex(int vertexIndex){
      System.out.print(lstVertices[vertexIndex].label+" ");
   }

   //get the adjacent unvisited vertex
   public int getAdjUnvisitedVertex(int vertexIndex){
      for(int i=0; i<vertexCount; i++)
         if(adjMatrix[vertexIndex][i]==1 && lstVertices[i].visited==false)
            return i;
      return -1;
   }

   public void depthFirstSearch(){
      //mark first node as visited
      lstVertices[0].visited = true;
      //display the vertex
      displayVertex(0);
      //push vertex index in stack
      stack.push(0);

      while(!stack.isEmpty()){
         //get the unvisited vertex of vertex which is at top of the stack
         int unvisitedVertex = getAdjUnvisitedVertex(stack.peek());
         //no adjacent vertex found
         if(unvisitedVertex == -1){
            stack.pop();
         }else{
            lstVertices[unvisitedVertex].visited = true;
            displayVertex(unvisitedVertex);
            stack.push(unvisitedVertex);
         }
      }

      //stack is empty, search is complete, reset the visited flag
      for(int i=0;i<vertexCount;i++){
         lstVertices[i].visited = false;
      }
   }

   public void breadthFirstSearch(){
      //mark first node as visited
      lstVertices[0].visited = true;
      //display the vertex
      displayVertex(0);
      //insert vertex index in queue
      queue.insert(0);
      int unvisitedVertex;
      while(!queue.isEmpty()){
         //get the unvisited vertex of vertex which is at front of the queue
         int tempVertex = queue.remove();
         //no adjacent vertex found
         while((unvisitedVertex=getAdjUnvisitedVertex(tempVertex)) != -1){
            lstVertices[unvisitedVertex].visited = true;
            displayVertex(unvisitedVertex);
            queue.insert(unvisitedVertex);
         }
      }

      //queue is empty, search is complete, reset the visited flag
      for(int i=0;i<vertexCount;i++){
         lstVertices[i].visited = false;
      }
   }
}

Demo Program

GraphDemo.java

package com.tutorialspoint.datastructure;

public class GraphDemo {
   public static void main(String args[]){
      Graph graph = new Graph();

      graph.addVertex('A');   //0
      graph.addVertex('B');   //1
      graph.addVertex('C');   //2
      graph.addVertex('D');   //3
      graph.addVertex('E');   //4
      graph.addVertex('F');   //5
      graph.addVertex('G');   //6

      /*       1  2  3
       * 0  |--B--C--D
       * A--|
       * |
       * |     4
       * |-----E
       * |     5  6
       * |  |--F--G
       * |--|
       */
      graph.addEdge(0, 1);   //AB
      graph.addEdge(1, 2);   //BC
      graph.addEdge(2, 3);   //CD
      graph.addEdge(0, 4);   //AC
      graph.addEdge(0, 5);   //AF
      graph.addEdge(5, 6);   //FG
      System.out.print("Depth First Search: ");
      //A B C D E F G
      graph.depthFirstSearch();
      System.out.println("");
      System.out.print("Breadth First Search: ");
      //A B E F C G D
      graph.breadthFirstSearch();
   }
}

如果我们编译并运行上述程序,它将生成以下结果 -

Depth First Search: A B C D E F G
Breadth First Search: A B E F C G D

DSA using Java - Search techniques

搜索是指在项目集合中找到指定属性的所需元素。我们将使用以下常用的简单搜索算法开始我们的讨论。

Sr.No

Technique & Description

1

Linear Search 线性搜索搜索所有项目,其最差执行时间为 n,其中 n 是项目数量。

2

Binary Search 二分搜索要求项目按顺序排列,但其最差执行时间是常数,并且比线性搜索快得多。

3

Interpolation Search 插值搜索要求项目按顺序排列,但其最差执行时间为 O(n),其中 n 是项目数量,并且比线性搜索快得多。

DSA using Java - Sorting techniques

排序是指以特定格式排列数据。排序算法指定了以特定顺序排列数据的途径。最常见的顺序是数字顺序或字典顺序。

排序的重要性在于,如果以排序的方式存储数据,则可以将数据搜索优化到很高水平。排序也可用于以更具可读性的格式表示数据。以下是在现实生活场景中排序的一些示例。

  1. Telephone Directory − 电话号码簿将人们的电话号码按照他们的姓名顺序排列。以便可以搜索名称。

  2. Dictionary − 字典将单词按字母顺序排列,以便在任何工作中找到它。

Types of Sorting

以下是流行排序算法及其比较的列表。

Sr.No

Technique & Description

1

Bubble Sort 冒泡排序是一种理解和实现算法的简单方法,但在性能上很差。

2

Selection Sort 选择排序,正如名称所指定的那样,使用技术来选择所需项目并相应地准备排序数组。

3

Insertion Sort 插入排序是选择排序的一个变种。

4

Shell Sort 希尔排序是插入排序的高效版本。

5

Quick Sort 快速排序是一种高效的排序算法,它基于将数据数组分成更小的数组。

6

Sorting Objects 可以使用 java.util.Arrays.sort() 来轻松地对 Java 对象进行排序。

DSA using Java - Recursion

Overview

递归是指编程语言中的一个技术,一个函数在其中调用它自身。调用自身的那个函数称为递归方法。

Characteristics

一个递归函数必须具有以下两个特性:

  1. Base Case(s)

  2. 导致在缩小情况后得出基本情况的规则集。

Recursive Factorial

阶乘是递归的一个经典示例。阶乘是一个满足以下条件的非负数。

阶乘表示为“!”。此处规则 1 和规则 2 是基本情况,而规则 3 是阶乘规则。

例如,3! = 3 x 2 x 1 = 6

private int factorial(int n){
   //base case
   if(n == 0){
      return 1;
   }else{
      return n * factorial(n-1);
   }
}

Recursive Fibonacci Series

斐波那契数列是递归的另一个经典示例。斐波那契数列是一个满足以下条件的整数数列。

斐波那契表示为“F”。此处规则 1 和规则 2 是基本情况,而规则 3 是斐波那契规则。

例如,F5 = 0 1 1 2 3

Demo Program

RecursionDemo.java

package com.tutorialspoint.algorithm;

public class RecursionDemo {
   public static void main(String[] args){
      RecursionDemo recursionDemo = new RecursionDemo();
      int n = 5;
      System.out.println("Factorial of " + n + ": "
         + recursionDemo.factorial(n));
      System.out.print("Fibbonacci of " + n + ": ");
      for(int i=0;i<n;i++){
         System.out.print(recursionDemo.fibbonacci(i) +" ");
      }
   }

   private int factorial(int n){
      //base case
      if(n == 0){
         return 1;
      }else{
         return n * factorial(n-1);
      }
   }

   private int fibbonacci(int n){
      if(n ==0){
         return 0;
      }
      else if(n==1){
         return 1;
      }
      else {
         return (fibbonacci(n-1) + fibbonacci(n-2));
      }
   }
}

如果我们编译并运行上述程序,它将生成以下结果 -

Factorial of 5: 120
Fibbonacci of 5: 0 1 1 2 3