数据结构-栈&队列&单向链表

来源:互联网 发布:ug五轴编程工资多少钱 编辑:程序博客网 时间:2024/05/22 08:22

栈(Stack)是一种先进后出的数据结构。栈对于数据的操作只能从栈顶进行操作,新放入的数据都位于栈顶,也就是第一的位置,以前放入的就会被向下压,所以数据入栈也叫做压栈

栈
出栈的形式与入栈类似,每次都只能获取栈顶的元素。如我们要取得“200”就必须先取出“300”,然后再取一次才能成功取得“200”.

public class Test01_Stack {    public static void main(String[] args) {        String[] data = {"a","b","c","d","e"};        Stack<String> stack = new Stack<String>();        for(String s:data){            stack.push(s);// 入栈的方法        }        for(int i=0;i<data.length;i++){            String s = stack.pop();// 出栈的方法            System.out.println(s);// e d c b a        }// Stack类还有其他三个常用操作方法,可以通过查询API了解其使用方法    }}
  • 使用栈的先进后出特性实现快速排序的非递归算法
public class Test03_quickSortNoRec {    public static void main(String[] args) {        int[] a = new int[20];        Random random = new Random();        for(int i=0;i<a.length;i++){            a[i] = random.nextInt(101);        }// 产生随机数组        System.out.println(Arrays.toString(a));        quickSort(a);// 排序        System.out.println(Arrays.toString(a));    }    private static void quickSort(int[] a) {        Stack<Node> stack = new Stack<>();// 创建栈对象        stack.push(new Node(0,a.length-1));// 压栈,获得第一次排序的边界        while(!stack.empty()){// 当栈中空时,相当于所有的子递归全部实现            Node node = stack.pop();//出栈,取得当前排序的边界,相当于一次递归            int left = node.left;            int right = node.right;            boolean isRight = false;// 快速排序算法代码            // 降序排序            while(left < right){                if(a[left] < a[right]){                    int t = a[left];                    a[left] = a[right];                    a[right] = t;                    isRight = !isRight;                }                if(isRight){                    right--;                }else{                    left++;                }            }            // 通过压栈,实现类似递归的功能            if(right+1 < node.right){                stack.push(new Node(right+1,node.right));            }            if(left-1 > node.left){                stack.push(new Node(node.left,left-1));            }        }    }}class Node{// 封装类,存储一次排序的左右边界    public int left;    public int right;    public Node(int left, int right) {        super();        this.left = left;        this.right = right;    }}

队列

队列是特殊的线性表,只允许在表的前端删除元素,在表的后端插入元素。所以队列是先进先出的数据结构。

  • 为什么要使用队列:
    • 计算机的任务调度系统
    • 为了削减高峰时期订单请求,使用消息队列
    • 其它数据结构比如树的广度优先遍历也需要借助队列来实现
    • Android中用于实现线程间通信的消息队列是队列的典型应用之一
// 自定义类实现队列特性,在Java中,可以将LinkedList类用作队列public class MyQueue<E> {    ArrayList<E> data = new ArrayList<E>();    public void push(E value){        data.add(value);    }    public E pop(){        E pop = data.remove(0);        return pop;    }    public boolean isEmpty(){        return data.size()==0;    }    public E peek(){        E peek = data.get(0);        return peek;    }    public int size(){        return data.size();    }}

链表(单向链表)

线性表是最基本、最简单、也最常用的一种数据结构。线性表中数据元素之间的关系是一对一的关系,即除了第一个和最后一个数据元素之外,其它数据元素都是首尾相接的。
一个链表是由节点组成的,类似于火车一样。每个链表(火车)有n个节点(车厢),一个节点内(车厢内)一部分内存(空间)用来存储数据值(乘客),还有一部分内存用来存储指向下一个节点的地址(通向下一节车厢的门的钥匙),我们通过访问这个地址(钥匙)就可以得到下一个节点(到达下一节车厢)。

// 自定义类实现链表的模拟public class Test06_LinkedList {    public static void main(String[] args) {    // 一个MyNode对象就是一个节点        MyNode<String> node = new MyNode<>("a");// 第一个节点        MyNode<String> head = node;// 头节点,火车头        // 第一个节点的next存放指向第二个节点的地址(钥匙)        node.next = new MyNode<>("b");        // 通过钥匙进入下一车厢        node = node.next;        // 第二个节点的next存放指向第三个节点的地址(钥匙)        node.next = new MyNode<>("c");        node = node.next;        // 回到头节点        node = head;        // 遍历链表        while(node!=null){            String str = node.value;// 取得节点存储的数据值            System.out.println(str);            node = node.next;// 跳向下一个节点        }    }}

节点类

public class MyNode<T> {    public T value;// 节点中存储的数据值    public MyNode<T> next;// 节点中存储的指向下一个节点的引用(钥匙)    public MyNode(T value) {        super();        this.value = value;    }    @Override    public String toString() {        return value.toString();    }}
  • 链表中删除节点
public class Test07_LinkedList2 {    public static void main(String[] args) {        String[] data = {"a","b","c","d","e"};        MyNode<String> node = new MyNode<String>(data[0]);        MyNode<String> head = node;        for(int i=1;i<data.length;i++){            node.next = new MyNode<String>(data[i]);            node = node.next;        }        Scanner scanner = new Scanner(System.in);        int select;        do{            System.out.println("1-删除首节点");            System.out.println("2-删除尾节点");            System.out.println("3-删除值为c的节点");            System.out.println("4-退出");            select = scanner.nextInt();            switch(select){            case 1:                head = deleteFirstNode(head);// 删除首节点                myPrint(head);                break;            case 2:                head = deleteLastNode(head);// 删除尾节点                myPrint(head);                break;            case 3:                try {                    head = deleteKeyNode(head,"e");// 删除指定值的节点                    myPrint(head);                } catch (Exception e) {                    System.out.println(e.getMessage());                }                break;            }        }while(select!=4);// 退出条件        scanner.close();    }    /**     * 删除指定值的节点     * @param head     * @throws Exception      */    private static MyNode<String> deleteKeyNode(MyNode<String> head, String key) throws Exception {        if(head == null){            throw new Exception("链表不能为空");        }        if(head.value.equals(key)){// 删除首节点的情况            head = deleteFirstNode(head);            return head;        }        MyNode<String> node = head.next;        MyNode<String> preNode = head;        while(node.next!=null){            if(node.value.equals(key)){// 删除中间节点的情况                preNode.next = node.next;                break;            }            preNode = node;            node = node.next;        }        if(node.value.equals(key)){// 删除尾节点的情况            preNode.next = null;            return head;        }        if(node.next==null){            throw new Exception("删除节点不存在");        }        return head;    }    /**     * 遍历链表,打印信息     * @param node     */    private static void myPrint(MyNode<String> node) {        while(node!=null){            System.out.println(node.value);            node = node.next;        }    }    /**     * 删除尾节点     * @param head     */    private static MyNode<String> deleteLastNode(MyNode<String> head) {        if(head==null || head.next==null){            return null;        }        MyNode<String> result = head;        while(head.next.next != null){            head = head.next;        }// 找到倒数第二个节点        head.next = null;// 删除最后一个节点        return result;    }    /**     * 删除首节点     * @param head     * @return     */    private static MyNode<String> deleteFirstNode(MyNode<String> head) {        if(head==null){            return null;        }        head = head.next;        return head;    }}

练习

2.合并两个有序的链表,合并的链表仍然有序。
解题思路:
node1={1,3,5,7,9,12}
node2={2,4,6,8,10,11,13};
外循环遍历node2链表
内循环遍历node1链表,每次判断node2是否能插入到node1链表中,
不能则node1遍历至下一个节点。
能则退出内循环,将node2插入到node1链表中。
node2遍历至下一个节点。

public class HomeWork01 {    public static void main(String[] args) {        int[] arr1 = {1,3,5,7,9,12};        int[] arr2 = {2,4,6,8,10,11,13};        MyNode<Integer> head1 = createLinkedList(arr1);// 创建第一个链表        MyNode<Integer> head2 = createLinkedList(arr2);// 创建第二个链表        merge(head1, head2);        myPrint(head1);    }    /**     * 合并链表     * @param head1    被插入的目标链表     * @param head2    用来插入的数据链表     */    private static void merge(MyNode<Integer> head1, MyNode<Integer> head2) {        while(head2!=null){            MyNode<Integer> node1=head1;// 获得被插入链表的首节点            int t = head2.value;// 获得要插入的链表的对应节点数据            MyNode<Integer> preNode=null;            while(node1!=null){                if(t <= node1.value){// 升序排序                    break;                }                preNode = node1;                node1=node1.next;            }            MyNode<Integer> insert = new MyNode<>(t);// 通过要插入的数据创建新的节点            preNode.next = insert;// 将新的节点插入到目标链表中            insert.next = node1;            head2 = head2.next;// 遍历数据链表,获得下一个需要插入的值        }    }    /**     * 遍历链表,打印信息     * @param head1     */    private static void myPrint(MyNode<Integer> head1) {        MyNode<Integer> node = head1;        while(node!=null){            System.out.print(node.value + " ");            node = node.next;        }    }    /**     * 创建链表     * @param arr1     * @return     */    private static MyNode<Integer> createLinkedList(int[] arr1) {        MyNode<Integer> node = new MyNode<Integer>(arr1[0]);        MyNode<Integer> head = node;        for(int i=1;i<arr1.length;i++){            node.next = new MyNode<Integer>(arr1[i]);            node = node.next;        }        return head;    }}
0 0
原创粉丝点击