常见数据结构及代码实现

1 Stack:栈

1.1 介绍

一种线性表,只允许在线性表的一端进行操作,即栈顶允许操作,而栈底不允许。像个桶状物,可以通过桶顶往桶里取放物品,而不能对桶底做什么,而且先放入桶中的物品总是在更底部,这就形成了栈的一个特性:先入后出。

1.2 时间复杂度

  • 入栈
    栈顶压入一个数据,O(1)
  • 出栈
    移除栈顶数据,O(1)

1.3 适用场景

先入而后出的特点和递归的使用十分契合。

1.4 代码实现

  • pop()
    出栈方法,即弹出栈顶数据
  • push()
    入栈方法,即往栈顶压入一个数据
  • peek()
    中文探出、偷看的意思,作用是返回当前栈顶数据,即查询栈顶数据

1.4.1 Java代码

仿造JDK1.8中Stack类源码的实现,

package structure;

import java.util.Arrays;
import java.util.EmptyStackException;

public class MyStack<E> {
    // 用于存放栈数据的数组容器
    private Object[] elementData;

    // 用于标记栈中数据的个数
    private int elementCount;

    // 用于指定当容器需要扩容时,每次扩容的大小
    private int capacityIncrement;

    public MyStack() {
        this(10); // 默认的初始容量大小为10
    }

    public MyStack(int initialCapacity) {
        this(initialCapacity, 0);
    }

    /**
     * @param initialCapacity   指定容器的初始容量大小
     * @param capacityIncrement 指定容器扩容幅度
     */
    public MyStack(int initialCapacity, int capacityIncrement) {
        this.elementData = new Object[initialCapacity];
        this.capacityIncrement = capacityIncrement;
    }

    public void push(E item) {
        if (this.elementCount + 1 > this.elementData.length) { // 当容器已满时进行扩容
            int oldCapacity = this.elementData.length;
            // 判断是否指定了扩容的幅度,未指定则默认进行2倍扩容(同源码)
            int newCapacity = oldCapacity + (capacityIncrement > 0 ? capacityIncrement : oldCapacity);
            this.elementData = Arrays.copyOf(this.elementData, newCapacity);
        }
        this.elementData[this.elementCount++] = item;
    }

    public void pop() {
        if (this.elementCount > 0) {
            this.elementCount--;
            this.elementData[this.elementCount] = null; // 垃圾回收
        }
    }

    @SuppressWarnings("unchecked")
    public E peek() {
        if (this.elementCount == 0) {
            throw new EmptyStackException();
        }
        return (E) this.elementData[this.elementCount - 1];
    }
}

1.4.2 Python代码

class MyStack:
    def __init__(self):
        self.element_data = []

    def push(self, item):
        self.element_data.append(item)

    def pop(self):
        self.element_data.pop()

    def peek(self):
        return self.element_data[len(self.element_data) - 1]

1.4.3 JavaScript代码

function MyStack(elementData = []) {
    this._elementData = elementData;
}
MyStack.prototype.push = function (item) {
    this._elementData.push(item);
};
MyStack.prototype.pop = function () {
    this._elementData.pop();
};
MyStack.prototype.peek = function () {
    return this._elementData[this._elementData.length - 1];
};

2 Queue:队列

2.1 介绍

一种线性表,允许在一端存数据,另一端取数据,这也构成了他的特性:先入先出。就像排队买票,先排队的先买到票,买到票的在前面离开队伍,需要买票的则在后面加入队伍。

2.2 时间复杂度

  • 入队
    在最后面添加一个元素,O(1)
  • 出队
    在最前面删除一个元素,O(1)

2.3 适用场景

根据先进先出的特点,适用于多线程阻塞队列管理。

2.4 代码实现

  • add()
    入队方法
  • remove()
    出队方发

2.4.1 Java代码

2.4.2.1 数组方式实现
package queue;

public class MyQueue {
    private Object[] elementData = new Object[10];
    private int elementCount;

    public void add(Object item) {
        this.elementData[this.elementCount++] = item;
    }

    public Object remove() {
        if (this.elementCount == 0) {
            throw new RuntimeException("the que is empty");
        }
        Object res = this.elementData[0];
        for (int i = 0; i < this.elementCount - 1 - 1; i++) {
            this.elementData[i] = this.elementData[i + 1];
        }
        this.elementData[this.elementCount - 1] = null;
        return res;
    }
}
2.4.1.2 列表方式实现
package queue;

import java.util.ArrayList;

public class MyQueue {
    private ArrayList<Object> elementData = new ArrayList<>();

    public void add(Object item) {
        this.elementData.add(item);
    }

    public Object remove() {
        if (this.elementData.isEmpty()) {
            throw new RuntimeException("the queue is empty");
        }
        return this.elementData.remove(0);
    }
}
2.4.1.3 两个栈组合实现

一个栈A负责入队,一个栈B负责出队,由于栈的特性先入后出,所以可以栈A中数据依次出栈、且同时入栈到栈B中,这样栈B出栈时,相当于总是移除栈A的栈底数据

package queue;

import java.util.Stack;

public class MyQueue {
    private Stack<Object> inStack = new Stack<>();
    private Stack<Object> outStack = new Stack<>();

    public void add(Object item) {
        this.inStack.push(item);
    }

    public Object remove() {
        if (this.outStack.isEmpty()) {
            while (this.inStack.size() > 0) {
                this.outStack.push(this.inStack.pop());
            }
        }
        return this.outStack.pop();
    }
}

2.4.2 Python代码

class MyQueue:
    def __init__(self):
        self.elementData = []

    def add(self, item):
        self.elementData.append(item)

    def remove(self):
        if self.elementData.__len__() > 0:
            target = self.elementData[0]
            self.elementData.remove(target)
            return target
            

2.4.3 JavaScript代码

function MyQueue(elementData=[]){
    this._elementData = elementData;
}
MyQueue.prototype.add = function (item) {
    this._elementData.push(item);
};
MyQueue.prototype.remove = function () {
    this._elementData.shift();
};

3 Heap:堆

3.1 介绍

对于堆的定义,需满足以下条件:

  1. 堆是棵完全二叉树
  2. 堆中某个节点的值总是不大于或不小于其父节点的值;
  • 称根节点值最小的堆为最小堆/小根堆;
  • 称根节点值最大的堆为最大堆/大根堆

3.2 时间复杂度

O(n),以小根堆为例,具体推导过程如下:

  1. 树每层的节点数最多为:
    2ⁿ⁻¹,n为层数
  2. 由1可得层数和节点数的关系为:
    h = log₂n + 1,n为节点数,h为层数
  3. 每层及对应的推导次数关系如下(先熟悉代码后此处会更容易理解)
层数最多需推导次数,h为总层数节点个数
1h - 12⁰
2h - 2
3h - 3
h-112ʰ⁻²
h02ʰ⁻¹
  1. 由3可得总的事件复杂度为:

      s = (h - 1) * 2⁰ + (h - 2) * 2¹ + (h - 3) * 2² + … + (1) * 2ʰ⁻² + (0) * 2ʰ⁻¹
         = (h - 1) * 2⁰ + (h - 2) * 2¹ + (h - 3) * 2² + … + (1) * 2ʰ⁻²


      2s = (h - 1) * 2¹ + (h - 2) * 2² + (h - 3) * 2³ + … + (2) * 2ʰ⁻² + (1) * 2ʰ⁻¹


      2s - s = - (h - 1) * 2⁰ + 2¹ + 2² + … + 2ʰ⁻² + 2ʰ⁻¹


      等比数列公式:Sₙ = a₁(1 - qⁿ) / (1 - q)


      2s - s = 1 - h + 2¹ * (1 - 2ʰ⁻¹) / (1 - 2)
                = 2ʰ⁻¹ - h - 1


      将 h = log₂n + 1 代入


      2ʰ⁻¹ - h - 1 = 2n - log₂n - 2


  1. 取最大影响因子并去除系数,得:
    O(n)

3.3 适用场景

堆排序、topN等

3.4 代码实现

  • create()
    创建堆方法(这里以创建最小堆为例)

3.4.1 Java代码

package structure.heap;

public class MyHeap {
    /**
     * 获取指定节点索引的左子节点索引
     *
     * @param todoNodeIndex 待处理节点索引
     * @return 待处理节点的左子节点索引
     */
    private int leftNodeIndex(int todoNodeIndex) {
        return (todoNodeIndex + 1) * 2 - 1;
    }

    /**
     * 获取指定节点索引的右子节点索引
     *
     * @param todoNodeIndex 待处理节点索引
     * @return 待处理节点的右子节点索引
     */
    private int rightNodeIndex(int todoNodeIndex) {
        return (todoNodeIndex + 1) * 2;
    }

    /**
     * 获取指定节点索引的父节点索引,就是求左子节点索引的反过程
     *
     * @param todoNodeIndex 待处理节点索引
     * @return 待处理节点的父节点索引
     */
    private int parentNodeIndex(int todoNodeIndex) {
        return (todoNodeIndex + 1) / 2 - 1;
    }

    /**
     * 用于创建堆
     * 
     * 思路是,判断指定父节点中,是否有子节点值比其还小,如果有则进行一次互换,
     * 以替换后的节点作为指定索引,重复前一步,直到该节点比子节点都要大时结束。
     * 
     * 每一次判断是否互换的过程就是一次推导过程
     *
     * @param heap          正在构建中的堆数组
     * @param todoNodeIndex 待进行推导的节点的索引
     */
    @SuppressWarnings("unchecked")
    private void adjust(Comparable[] heap, int todoNodeIndex) {
        int leftNodeIndex = leftNodeIndex(todoNodeIndex);
        int rightNodeIndex = rightNodeIndex(todoNodeIndex);
        int smallestNodeValueIndex = todoNodeIndex; //先假定最小节点值对应的索引为父节点索引
        if (leftNodeIndex < heap.length) { //有可能子节点的索引超出heap索引范围,如最后一层节点的子节点索引
            smallestNodeValueIndex = heap[smallestNodeValueIndex].compareTo(heap[leftNodeIndex]) > 0 ? leftNodeIndex : smallestNodeValueIndex;
        }
        if (rightNodeIndex < heap.length) {
            smallestNodeValueIndex = heap[smallestNodeValueIndex].compareTo(heap[rightNodeIndex]) > 0 ? rightNodeIndex : smallestNodeValueIndex;
        }
        if (smallestNodeValueIndex == todoNodeIndex) return; //当父节点节点值比子节点的节点值都要大时本次推导结束
        //执行替换操作
        Comparable smallNodeValue = heap[smallestNodeValueIndex];
        heap[smallestNodeValueIndex] = heap[todoNodeIndex];
        heap[todoNodeIndex] = smallNodeValue;
        adjust(heap, smallestNodeValueIndex);// 继续推导
    }

    /**
     * 创建堆
     *
     * @param arr 用于创建成堆的数组
     */
    public void create(Comparable[] arr) {
        if (arr.length < 2) return;
        // 从后向前推导,先求最后一个有子节点的父节点索引,即最后一个索引的父节点索引
        int parentNodeIndex = parentNodeIndex(arr.length - 1);
        for (int i = parentNodeIndex; i >= 0; i--) {
            adjust(arr, i);
        }
    }
}

package structure;

import org.junit.Test;
import structure.heap.MyHeap;

import java.util.Arrays;

public class MyHeapTest {
    @Test
    public void test(){
        MyHeap heap = new MyHeap();
        Comparable[] arr = {19, 5, 12, 9, 15, 16, 7, 21, 9};
        heap.create(arr);
        System.out.println(Arrays.toString(arr));
        // [5, 9, 7, 9, 15, 16, 12, 21, 19]
    }
}

3.4.2 Python代码

def get_left_node_index(todo_node_index):
    return (todo_node_index + 1) * 2 - 1


def get_right_node_index(todo_node_index):
    return (todo_node_index + 1) * 2


def get_parent_node_index(todo_node_index):
    return (todo_node_index + 1) // 2 - 1


def adjust(todo_node_index, heap):
    left_node_index = get_left_node_index(todo_node_index)
    right_node_index = get_right_node_index(todo_node_index)
    smallest_node_index = todo_node_index
    if left_node_index < len(heap):
        smallest_node_index = [smallest_node_index, left_node_index][heap[smallest_node_index] > heap[left_node_index]]
    if right_node_index < len(heap):
        smallest_node_index = [smallest_node_index, right_node_index][heap[smallest_node_index] > heap[right_node_index]]
    if smallest_node_index == todo_node_index:
        return
    heap[todo_node_index], heap[smallest_node_index] = heap[smallest_node_index], heap[todo_node_index]
    adjust(smallest_node_index, heap)


def create(arr):
    if len(arr) < 2: return
    parent_node_index = get_parent_node_index(len(arr) - 1)
    for index in range(parent_node_index, -1, -1):
        adjust(index, arr)


if __name__ == '__main__':
    arr = [19, 5, 12, 9, 15, 16, 7, 21, 9]
    create(arr)
    print(arr)  # [5, 9, 7, 9, 15, 16, 12, 21, 19]

3.4.3 JavaScript代码

let getLeftNodeIndex = (todoNodeIndex => (todoNodeIndex + 1) * 2 - 1);
let getRightNodeIndex = (todoNodeIndex => (todoNodeIndex + 1) * 2);
let getParentNodeIndex = (todoNodeIndex => parseInt((todoNodeIndex + 1) / 2 + "") - 1);
let adjust = ((heap, todoNodeIndex) => {
    let leftNodeIndex = getLeftNodeIndex(todoNodeIndex);
    let rightNodeIndex = getRightNodeIndex(todoNodeIndex);
    let smallestNodeIndex = todoNodeIndex;
    if (leftNodeIndex < heap.length) smallestNodeIndex = heap[smallestNodeIndex] > heap[leftNodeIndex] ? leftNodeIndex : smallestNodeIndex;
    if (rightNodeIndex < heap.length) smallestNodeIndex = heap[smallestNodeIndex] > heap[rightNodeIndex] ? rightNodeIndex : smallestNodeIndex;
    if (smallestNodeIndex === todoNodeIndex) return;
    [heap[todoNodeIndex], heap[smallestNodeIndex]] = [heap[smallestNodeIndex], heap[todoNodeIndex]];
    adjust(heap, smallestNodeIndex);
});
let create = (heap => {
    let parentNodeIndex = getParentNodeIndex(heap.length - 1);
    for (let i = parentNodeIndex; i >= 0; i--) {
        adjust(heap, i);
    }
});

let arr = [9, 5, 12, 9, 15, 16, 7, 21, 19];
create(arr);
console.log(arr); //[5,  9,  7,  9, 15, 16, 12, 21, 19]

4 BinarySearchTree:二叉查找树

4.1 介绍

二叉查找树,又称二叉搜索树,亦称二叉排序树,他有如下特点:

  • 首先它是个二叉树
  • 其次树中的任一节点总是大于其左子树的任一节点,小于其右子树的任一节点
  • 如图:
    在这里插入图片描述

4.2 时间复杂度

二叉查找树的时间复杂度,通常指查找节点的时间复杂度,这分为两种情况,如果这颗二叉树是平衡的,由树高和节点数的关系:h = log₂n + 1 知,最多需要比较 log₂n + 1 次,即时间复杂度为:O(log₂n),但是可能有极端情况,如正序或倒序将一批数据(如:1,2,3,4,5)依次添加构建成树,那么树的形状将是这样的:
在这里插入图片描述

此时树高将是 n,时间复杂度为:O(n)。

4.3 使用场景

由于二叉查找树存在最差时间复杂度:O(n)情况,所以在应用上,更多的是使用基于二叉查找树、并经过优化的平衡二叉树、红黑树等。

4.4 代码实现

  • add()
    添加节点方法
  • search()
    查找节点方法
  • remove()
    删除节点方法
  • show()
    展示所有节点,通过中序遍历方式,可以顺序输出,相当于实现了排序

4.4.1 Java代码实现

package structure.tree;

import java.util.Optional;

public class MyBinarySearchTree {

    public class Node {
        public Comparable value;
        public Node leftNode;
        public Node rightNode;

        Node(Comparable value) {
            this.value = value;
        }

        /**
         * 添加节点的具体实现
         * 注意这里为了方便,对于相同的节点值只进行添加一次
         *
         * @param node 待添加的节点
         */
        @SuppressWarnings("unchecked")
        private void addNode(Node node) {
            if (node.value.compareTo(this.value) > 0) { //如果待添加的节点比当前节点大,说明待添加节点应该放在当前节点右子树上
                if (null == this.rightNode) { //如果当前节点尚无右节点
                    this.rightNode = node;
                } else {
                    this.rightNode.addNode(node);
                }

            } else if (node.value.compareTo(this.value) < 0) { //如果待添加的节点比当前节点小,说明待添加节点应该放在当前节点左子树上
                if (null == this.leftNode) { //如果当前节点尚无左节点
                    this.leftNode = node;
                } else {
                    this.leftNode.addNode(node);
                }
            }
        }

        /**
         * 查找节点的具体实现
         *
         * @param value 待查找节点的节点值
         * @return 查找到的节点,找不到则返回null
         */
        @SuppressWarnings("unchecked")
        private Optional<Node> searchNode(Comparable value) {
            if (value.compareTo(this.value) == 0) {
                return Optional.of(this);
            } else if (value.compareTo(this.value) > 0 && null != this.rightNode) {
                return this.rightNode.searchNode(value);
            } else if (value.compareTo(this.value) < 0 && null != this.leftNode) {
                return this.leftNode.searchNode(value);
            }
            return Optional.empty();
        }

        /**
         * 删除节点具体实现
         *
         * @param node 待删除节点
         */
        private void removeNode(Node node) {
            Node parentNode = searchParentNode(node);//获取父节点
            if (null == node.leftNode && null == node.rightNode){ //如果要删除的节点是叶子结点:没有左子节点,也没有右子节点
                if (null == parentNode){ //如果删除的是根节点
                    MyBinarySearchTree.this.rootNode = null;
                } else { //如果删除的是非根节点
                    if (node == parentNode.leftNode) {
                        parentNode.leftNode = null;
                    } else {
                        parentNode.rightNode = null;
                    }
                }
            } else if(null != node.leftNode && null != node.rightNode){ //如果要删除的节点同时有左右节点
                /*
                 * 删除方式是:找到右子树最小节点(或左子树最大节点),删除掉,并将值赋给被删除节点
                 * */
                Node rightTreeMinNode = searchMinNode(node.rightNode);
                removeNode(rightTreeMinNode);
                node.value = rightTreeMinNode.value;
            } else { //如果要删除的节点存在左子节点或右子节点
                if (null == parentNode){
                    if (null != node.leftNode){
                        MyBinarySearchTree.this.rootNode = MyBinarySearchTree.this.rootNode.leftNode;
                    } else {
                        MyBinarySearchTree.this.rootNode = MyBinarySearchTree.this.rootNode.rightNode;
                    }
                } else {
                    if (null != node.leftNode) {
                        if (node == parentNode.leftNode){
                            parentNode.leftNode = node.leftNode;
                        } else {
                            parentNode.rightNode = node.leftNode;
                        }
                    } else {
                        if (node == parentNode.leftNode){
                            parentNode.leftNode = node.rightNode;
                        } else {
                            parentNode.rightNode = node.rightNode;
                        }
                    }
                }
            }
        }

        /**
         * 查找指定节点的父节点
         *
         * @param node 指定节点
         * @return 找到的指定节点的父节点,找不到返回null
         */
        @SuppressWarnings("unchecked")
        private Node searchParentNode(Node node) {
            if (null == node) return null;
            if ((null != this.leftNode && this.leftNode == node) || (null != this.rightNode && this.rightNode == node)) {
                return this;
            } else if (node.value.compareTo(this.value) < 0 && null != this.leftNode) {
                return this.leftNode.searchParentNode(node);
            } else if (node.value.compareTo(this.value) > 0 && null != this.rightNode) {
                return this.rightNode.searchParentNode(node);
            }
            return null;
        }


        /**
         * 查找指定节点的最小子节点
         *
         * @param node 指定节点
         * @return 找到的指定节点的最小子节点
         */
        private Node searchMinNode(Node node) {
            if (null == node) return null;
            if (null == node.leftNode) return node;
            else return searchMinNode(node.leftNode);
        }

        /**
         * 通过中序排序方式从小到大展示二叉树的所有节点值
         */
        private void middleOrderShow(Node node) {
            if (null == node) return;
            middleOrderShow(node.leftNode);
            System.out.print(node.value + "  ");
            middleOrderShow(node.rightNode);
        }
    }

    /**
     * 根节点
     */
    private Node rootNode;

    /**
     * 添加节点方法
     * 通过输入节点值来添加节点
     *
     * @param value 输入的节点值
     */
    public void add(Comparable value) {
        Node newNode = new Node(value);
        if (null == this.rootNode) this.rootNode = newNode;
        else this.rootNode.addNode(newNode);
    }

    /**
     * 查找节点方法
     * 通过输入节点值来查找对应的节点
     *
     * @param value 输入的节点值
     * @return 查找到的节点,找不到则返回null
     */
    public Node search(Comparable value) {
        if (null == this.rootNode) return null;
        Optional<Node> target = this.rootNode.searchNode(value);
        return target.orElse(null);
    }

    /**
     * 删除节点
     * 通过输入节点值来删除对应的节点
     *
     * @param value 输入的节点值
     */
    public void remove(Comparable value) {
        if (null == this.rootNode) return;
        /*先找到要删除的节点*/
        Node targetNode = search(value);
        if (null == targetNode) return;
        this.rootNode.removeNode(targetNode);
    }

    /**
     * 展示所有节点
     */
    public void show(){
        if (null == this.rootNode) return;
        System.out.print("[  ");
        this.rootNode.middleOrderShow(this.rootNode);
        System.out.print("]");
        System.out.println();
    }
}

package structure;

import org.junit.Test;
import structure.tree.MyBinarySearchTree;

public class MyBinarySearchTreeTest {
    @Test
    public void test(){
        MyBinarySearchTree tree = new MyBinarySearchTree();
        Comparable[] values = {5, 2, 16, 8, 1, 19, 3, 15, 10, 21, 16, 23};
        for (Comparable value : values) {
            tree.add(value);
        }
        tree.show(); //[  1  2  3  5  8  10  15  16  19  21  23  ]
        MyBinarySearchTree.Node root = tree.search(5);
        System.out.println(root.leftNode.value); //2
        System.out.println(root.rightNode.value); //16
        tree.remove(16);
        System.out.println(root.rightNode.value); //19
        tree.show(); //[  1  2  3  5  8  10  15  19  21  23  ]
    }
}

4.4.2 Python代码实现

class Node:
    def __init__(self, value: int):
        self.value = value
        self.left_node = None
        self.right_node = None

    def add_node(self, node):
        if node.value < self.value:
            if not self.left_node:
                self.left_node = node
            else:
                self.left_node.add_node(node)
        elif node.value > self.value:
            if not self.right_node:
                self.right_node = node
            else:
                self.right_node.add_node(node)

    def search_node(self, value):
        if value == self.value:
            return self
        elif value < self.value and self.left_node:
            return self.left_node.search_node(value)
        elif value > self.value and self.right_node:
            return self.right_node.search_node(value)

    def search_parent_node(self, node):
        if not node:
            return
        if self.left_node == node or self.right_node == node:
            return self
        elif node.value < self.value and self.left_node:
            return self.left_node.search_parent_node(node)
        elif node.value > self.value and self.right_node:
            return self.right_node.search_parent_node(node)

    def search_min_node(self, node):
        if node:
            if not node.left_node:
                return node
            else:
                return self.search_min_node(node.left_node)

    def middle_order_show(self, node):
        if node:
            self.middle_order_show(node.left_node)
            print(node.value, end=",")
            self.middle_order_show(node.right_node)


class MyBinarySearchTree:
    root_node = None

    def add(self, value: int):
        new_node = Node(value)
        if self.root_node is None:
            self.root_node = new_node
        else:
            self.root_node.add_node(new_node)

    def search(self, value: int):
        if self.root_node is not Node:
            return self.root_node.search_node(value)

    def remove(self, value: int):
        if self.root_node is Node:
            return
        target_node = self.root_node.search_node(value)
        if not target_node:
            return
        parent_node = self.root_node.search_parent_node(target_node)
        if not target_node.left_node and not target_node.right_node:
            if not parent_node:
                self.root_node = None
            else:
                if target_node == parent_node.left_node:
                    parent_node.left_node = None
                else:
                    parent_node.right_node = None
        elif target_node.left_node and target_node.right_node:
            right_tree_min_node = self.root_node.search_min_node(target_node.right_node)
            self.remove(right_tree_min_node.value)
            target_node.value = right_tree_min_node.value
        else:
            if not parent_node:
                if target_node.left_node:
                    self.root_node = target_node.left_node
                else:
                    self.root_node = target_node.right_node
            else:
                if target_node.left_node:
                    if target_node == parent_node.left_node:
                        parent_node.left_node = target_node.left_node
                    else:
                        parent_node.right_node = target_node.left_node
                else:
                    if target_node == parent_node.left_node:
                        parent_node.left_node = target_node.right_node
                    else:
                        parent_node.right_node = target_node.right_node

    def show(self):
        if self.root_node is not None:
            self.root_node.middle_order_show(self.root_node)
            print()


if __name__ == '__main__':
    tree = MyBinarySearchTree()
    for value in [5, 2, 16, 8, 1, 19, 3, 15, 10, 21, 16, 23]:
        tree.add(value)
    tree.show()  # 1, 2, 3, 5, 8, 10, 15, 16, 19, 21, 23
    root = tree.search(5)
    print(root.left_node.value)  # 2
    print(root.right_node.value)  # 16
    tree.remove(16)
    print(root.right_node.value)  # 19
    tree.show()  # 1, 2, 3, 5, 8, 10, 15, 19, 21, 23

4.4.3 JavaScript代码实现

function Node(value) {
    this.value = value;
    this.leftNode = null;
    this.rightNode = null;
}

Node.prototype.addNode = function (node) {
    if (node.value < this.value) {
        if (null == this.leftNode) this.leftNode = node;
        else this.leftNode.addNode(node);
    } else if (node.value > this.value) {
        if (null == this.rightNode) this.rightNode = node;
        else this.rightNode.addNode(node);
    }
};

Node.prototype.searchNode = function (value) {
    if (value === this.value) return this;
    else if (value < this.value && this.leftNode) {
        return this.leftNode.searchNode(value);
    } else if (value > this.value && this.rightNode) {
        return this.rightNode.searchNode(value);
    } else {
        return null;
    }
};

Node.prototype.searchParentNode = function (node) {
    if (null === node) return null;
    if (node === this.leftNode || node === this.rightNode) return this;
    else if (node.value < this.value && this.leftNode) return this.leftNode.searchParentNode(node);
    else if (node.value > this.value && this.rightNode) return this.rightNode.searchParentNode(node);
    else return null;
};

Node.prototype.searchMinNode = function (node) {
    if (!node) return null;
    if (null === node.leftNode) return node;
    else return this.searchMinNode(node.leftNode);
};

Node.prototype.middleOrderShow = function (node) {
    if (!node) return;
    this.middleOrderShow(node.leftNode);
    console.log(node.value);
    this.middleOrderShow(node.rightNode);
};


function MyBinarySearchTree() {
    this.rootNode = null;
}

MyBinarySearchTree.prototype.add = function (value) {
    let newNode = new Node(value);
    if (null == this.rootNode) this.rootNode = newNode;
    else this.rootNode.addNode(newNode);
};

MyBinarySearchTree.prototype.search = function (value) {
    if (null == this.rootNode) return;
    return this.rootNode.searchNode(value);
};

MyBinarySearchTree.prototype.remove = function (value) {
    if (null == this.rootNode) return;
    let targetNode = this.rootNode.searchNode(value);
    if (!targetNode) return;
    let parentNode = this.rootNode.searchParentNode(targetNode);
    if (!targetNode.leftNode && !targetNode.rightNode) {
        if (!parentNode) {
            this.rootNode = null;
        } else {
            if (targetNode === parentNode.leftNode) parentNode.leftNode = null;
            else parentNode.rightNode = null;
        }
    } else if (targetNode.leftNode && targetNode.rightNode) {
        let rightTreeMinNode = this.rootNode.searchMinNode(targetNode.rightNode);
        this.remove(rightTreeMinNode.value);
        targetNode.value = rightTreeMinNode.value;
    } else {
        if (!parentNode) {
            if (targetNode.leftNode) this.rootNode = this.rootNode.leftNode;
            else this.rootNode = this.rootNode.rightNode;
        } else {
            if (targetNode.leftNode) {
                if (targetNode === parentNode.leftNode) {
                    parentNode.leftNode = targetNode.leftNode;
                } else {
                    parentNode.rightNode = targetNode.leftNode;
                }
            } else {
                if (targetNode === parentNode.leftNode) {
                    parentNode.leftNode = targetNode.rightNode;
                } else {
                    parentNode.rightNode = targetNode.rightNode;
                }
            }
        }
    }
};

MyBinarySearchTree.prototype.show = function () {
    if (null != this.rootNode) this.rootNode.middleOrderShow(this.rootNode)
};

let tree = new MyBinarySearchTree();
let values = [5, 2, 16, 8, 1, 19, 3, 15, 10, 21, 16, 23];
values.forEach(value => tree.add(value));
tree.show();  // 1, 2, 3, 5, 8, 10, 15, 16, 19, 21, 23
let root = tree.search(5);
console.log(root.leftNode.value);  // 2
console.log(root.rightNode.value);  // 16
tree.remove(16);
console.log(root.rightNode.value);  // 19
tree.show();  // 1, 2, 3, 5, 8, 10, 15, 19, 21, 23

5 SinglyLinkedList:单向链表

5.1 介绍

和其他链表(还有单向循环链表、双向链表、双向循环链表)一样,单向链表也是由众多的节点组成,其中单向链表的每个节点又有两个组成部分:数据域和引用域

  • 数据域
    存储着具体的数据值
  • 引用域
    存储着下一个数据的地址,并且最后一个节点的引用域为null

在这里插入图片描述

5.2 时间复杂度

这个很好理解,无论添加节点、删除节点、更新节点、获取节点,都是从第一个节点开始往后找,直到直到目标,所以最坏的情况就是找到最后一个节点处,此时时间复杂度都为O(n)

5.3 代码实现

  • add()
    添加节点
  • remove()
    根据 节点值/索引 移除节点
  • update()
    根据 节点值/索引 更新节点
  • get()
    根据 指定索引 获取对应的节点
  • size()
    获取节点个数
  • show()
    遍历,展示所有节点

5.3.1 Java代码实现

package structure.linkedlist;

public class MySinglyLinkedList<E> {
    class Node {
        E value;
        Node nextNode;

        Node(E value) {
            this.value = value;
        }

        private void addNode(Node node) {
            if (null == this.nextNode) this.nextNode = node;
            else this.nextNode.addNode(node);
        }

        private void removeNode(E value) {
            Node currentNode = this.nextNode;
            if (null == currentNode) return;
            if (value.equals(currentNode.value)) {
                this.nextNode = currentNode.nextNode;
                MySinglyLinkedList.this.nodeCount--;
            } else {
                this.nextNode.removeNode(value);
            }
        }

        private void removeNode(int index) {
            //在此之前已经对index进行了判断
            Node currentNode = this.nextNode;
            int currentIndex = ++MySinglyLinkedList.this.firstNodeIndex;
            if (currentIndex == index) {
                this.nextNode = currentNode.nextNode;
                MySinglyLinkedList.this.nodeCount--;
            } else {
                this.nextNode.removeNode(index);
            }
        }

        private void updateNode(E oldValue, E newValue) {
            if (oldValue.equals(this.value)) {
                this.value = newValue;
            } else {
                if (null != this.nextNode) {
                    this.nextNode.updateNode(oldValue, newValue);
                }
            }
        }

        private void updateNode(int index, E newValue){
            //在此之前已经对index进行了判断
            int currentIndex = ++MySinglyLinkedList.this.firstNodeIndex;
            if (currentIndex == index) {
                this.nextNode.value = newValue;
            } else {
                this.nextNode.updateNode(index, newValue);
            }
        }

        private E getNode(int index){
            //在此之前已经对index进行了判断
            int currentIndex = ++MySinglyLinkedList.this.firstNodeIndex;
            if (currentIndex == index) {
                return this.nextNode.value;
            } else {
                return this.nextNode.getNode(index);
            }
        }

        private void showNodes(){
            if (null != this.nextNode) {
                System.out.print(this.value + ", ");
                this.nextNode.showNodes();
            } else {
                System.out.print(this.value);
            }
        }
    }

    /**
     * 第一个节点
     */
    private Node firstNode;

    /**
     * 第一个节点的索引值
     */
    private int firstNodeIndex;

    /**
     * 节点数
     */
    private int nodeCount;

    public void add(E value) {
        Node newNode = new Node(value);
        if (null == this.firstNode) {
            this.firstNode = newNode;
        } else {
            this.firstNode.addNode(newNode);
        }
        this.nodeCount++;
    }

    /**
     * 根据节点值来删除节点
     *
     * @param value 要删除的节点的节点值
     */
    public void remove(E value) {
        if (null == this.firstNode) {
            throw new RuntimeException("list is empty!");
        }
        if (value.equals(this.firstNode.value)) {
            this.firstNode = this.firstNode.nextNode;
            this.nodeCount--;
        } else {
            this.firstNode.removeNode(value);
        }
    }

    /**
     * 根据节点索引来删除节点
     *
     * @param index 要删除的节点的索引
     */
    public void remove(int index) {
        if (index < 0 || index >= this.nodeCount) {
            throw new IndexOutOfBoundsException();
        }
        if (null == this.firstNode) {
            throw new RuntimeException("list is empty!");
        }
        if (0 == index) {
            this.firstNode = this.firstNode.nextNode;
            this.nodeCount--;
        } else {
            this.firstNodeIndex = 0;
            this.firstNode.removeNode(index);
        }
    }

    /**
     * 根据节点值进行更新操作
     *
     * @param oldValue 旧的节点值
     * @param newValue 新的节点值
     */
    public void update(E oldValue, E newValue) {
        if (null == this.firstNode) {
            throw new RuntimeException("list is empty!");
        }
        if (oldValue.equals(this.firstNode.value)) {
            this.firstNode.value = newValue;
        } else {
            this.firstNode.updateNode(oldValue, newValue);
        }
    }

    /**
     * 根据节点索引进行更新操作
     *
     * @param index    待更新节点的索引
     * @param newValue 新的节点值
     */
    public void update(int index, E newValue) {
        if (index < 0 || index >= this.nodeCount) {
            throw new IndexOutOfBoundsException();
        }
        if (null == this.firstNode) {
            throw new RuntimeException("list is empty!");
        }
        if (0 == index) {
            this.firstNode.value = newValue;
        } else {
            this.firstNodeIndex = 0;
            this.firstNode.updateNode(index, newValue);
        }
    }

    public E get(int index) {
        if (index < 0 || index >= this.nodeCount) {
            throw new IndexOutOfBoundsException();
        }
        if (null == this.firstNode) {
            throw new RuntimeException("list is empty!");
        }
        if (0 == index) return this.firstNode.value;
        else {
            this.firstNodeIndex = 0;
            return this.firstNode.getNode(index);
        }
    }

    public int size() {
        if (null == this.firstNode) {
            throw new RuntimeException("list is empty!");
        }
        return this.nodeCount;
    }

    public void show() {
        if (null == this.firstNode) {
            throw new RuntimeException("list is empty!");
        }
        System.out.print("[");
        this.firstNode.showNodes();
        System.out.print("]");
        System.out.println();
    }
}

package structure;

import org.junit.Test;
import structure.linkedlist.MySinglyLinkedList;

public class MySinglyLinkedListTest {
    @Test
    public void test(){
        MySinglyLinkedList<String> list = new MySinglyLinkedList<>();

        /*1.测试添加数据*/
        String[] values = {"c", "b", "a", "aa", "bb", "cc", "a", "b", "c"};
        for (String value: values) {
            list.add(value);
        }
        System.out.println(list.size()); //9
        list.show(); //[c, b, a, aa, bb, cc, a, b, c]

        /*2.测试删除数据*/
        /*2.1.索引方式删除第一个数据*/
        list.remove(0);
        System.out.println(list.size()); //8
        list.show(); //[b, a, aa, bb, cc, a, b, c]
        /*2.2.索引方式删除非第一个数据*/
        list.remove(2);
        System.out.println(list.size()); //7
        list.show(); //[b, a, bb, cc, a, b, c]
        /*2.3.节点值方式删除第一个数据*/
        list.remove("b");
        System.out.println(list.size()); //6
        list.show(); //[a, bb, cc, a, b, c]
        /*2.4.节点值方式删除非第一个数据*/
        list.remove("c");
        System.out.println(list.size()); //5
        list.show(); //[a, bb, cc, a, b]

        /*3.测试修改数据*/
        /*3.1.索引方式修改第一个数据*/
        list.update(0, "aaa");
        list.show(); //[aaa, bb, cc, a, b]
        /*3.2.索引方式修改非第一个数据*/
        list.update(2, "ccc");
        list.show(); //[aaa, bb, ccc, a, b]
        /*3.3.节点值方式修改第一个数据*/
        list.update("aaa", "aa");
        list.show(); //[aa, bb, ccc, a, b]
        /*3.4.节点值方式修改非第一个数据*/
        list.update("ccc", "cc");
        list.show(); //[aa, bb, cc, a, b]

        /*4.测试获取数据*/
        /*4.1.获取第一个数据*/
        System.out.println(list.get(0)); //aa
        /*4.2.获取非第一个数据*/
        System.out.println(list.get(2)); //cc
    }
}

5.3.2 Python代码实现

class Node:
    def __init__(self, value, next_node=None):
        self.value = value
        self.next_node = next_node

    def add_node(self, node):
        if not self.next_node:
            self.next_node = node
        else:
            self.next_node.add_node(node)

    def remove_node_by_value(self, value) -> int:
        current_node = self.next_node
        if not current_node:
            return 0
        if value == current_node.value:
            self.next_node = current_node.next_node
            return -1
        else:
            return self.next_node.remove_node_by_value(value)

    def remove_node_by_index(self, index, first_node_index=0) -> int:
        current_node = self.next_node
        current_node_index = first_node_index + 1
        if not current_node:
            return 0
        if current_node_index == index:
            self.next_node = current_node.next_node
            return -1
        else:
            return self.next_node.remove_node_by_index(index, current_node_index)

    def update_node_by_value(self, old_value, new_value):
        if not self.next_node:
            return
        if self.next_node.value == old_value:
            self.next_node.value = new_value
        else:
            self.next_node.update_node_by_value(old_value, new_value)

    def update_node_by_index(self, index, new_value, first_node_index=0):
        if not self.next_node:
            return
        current_node_index = first_node_index + 1
        if current_node_index == index:
            self.next_node.value = new_value
        else:
            self.next_node.update_node_by_index(index, new_value, current_node_index)

    def get_node(self, index, first_node_index=0):
        if not self.next_node:
            return
        current_node_index = first_node_index + 1
        if current_node_index == index:
            return self.next_node.value
        else:
            return self.next_node.get_node(index, current_node_index)


class MySinglyLinkedList:
    first_node = None
    node_count = 0

    def add(self, value):
        new_node = Node(value)
        if self.first_node is None:
            self.first_node = new_node
        else:
            self.first_node.add_node(new_node)
        self.node_count += 1

    def remove_by_value(self, value):
        if self.first_node is None:
            raise Exception("list is empty!")
        if value == self.first_node.value:
            self.first_node = self.first_node.next_node
            self.node_count -= 1
        else:
            self.node_count += self.first_node.remove_node_by_value(value)

    def remove_by_index(self, index: int):
        if index < 0 or index >= self.node_count:
            raise IndexError('list index out of range')
        if self.first_node is None:
            raise Exception("list is empty!")
        if 0 == index:
            self.first_node = self.first_node.next_node
            self.node_count -= 1
        else:
            self.node_count += self.first_node.remove_node_by_index(index)

    def update_by_value(self, old_value, new_value):
        if self.first_node is None:
            raise Exception("list is empty!")
        if self.first_node.value == old_value:
            self.first_node.value = new_value
        else:
            self.first_node.update_node_by_value(old_value, new_value)

    def update_by_index(self, index: int, new_value):
        if index < 0 or index >= self.node_count:
            raise IndexError('list index out of range')
        if self.first_node is None:
            raise Exception("list is empty!")
        if 0 == index:
            self.first_node.value = new_value
        else:
            self.first_node.update_node_by_index(index, new_value)

    def get(self, index: int):
        if index < 0 or index >= self.node_count:
            raise IndexError('list index out of range')
        if self.first_node is None:
            raise Exception("list is empty!")
        if 0 == index:
            return self.first_node.value
        else:
            return self.first_node.get_node(index)

    def size(self) -> int:
        if self.first_node is None:
            raise Exception("list is empty!")
        return self.node_count

    def show(self):
        if self.first_node is None:
            raise Exception("list is empty!")
        current_node = self.first_node
        print('[', end='')
        while current_node:
            print(current_node.value, end=[', ', ''][current_node.next_node is None])
            current_node = current_node.next_node
        print(']', end='')
        print()


if __name__ == '__main__':
    li = MySinglyLinkedList()
    """1.测试添加数据"""
    for value in ["c", "b", "a", "aa", "bb", "cc", "a", "b", "c"]:
        li.add(value)
    li.show()  # [c, b, a, aa, bb, cc, a, b, c]

    """2.测试删除数据"""
    '''2.1.索引方式删除第一个数据'''
    li.remove_by_index(0)
    li.show()  # [b, a, aa, bb, cc, a, b, c]
    '''2.2.索引方式删除非第一个数据'''
    li.remove_by_index(2)
    li.show()  # [b, a, bb, cc, a, b, c]
    '''2.3.节点值方式删除第一个数据'''
    li.remove_by_value('b')
    li.show()  # [a, bb, cc, a, b, c]
    '''2.4.节点值方式删除非第一个数据'''
    li.remove_by_value('c')
    li.show()  # [a, bb, cc, a, b]

    """3.测试修改数据"""
    '''3.1.索引方式修改第一个数据'''
    li.update_by_index(0, "aaa")
    li.show()  # [aaa, bb, cc, a, b]
    '''3.2.索引方式修改非第一个数据'''
    li.update_by_index(2, "ccc")
    li.show()  # [aaa, bb, ccc, a, b]
    '''3.3.节点值方式修改第一个数据'''
    li.update_by_value('aaa', "aa")
    li.show()  # [aa, bb, ccc, a, b]
    '''3.4.节点值方式修改非第一个数据'''
    li.update_by_value("ccc", 'cc')
    li.show()  # [aa, bb, cc, a, b]

    """4.测试获取数据"""
    '''4.1.获取第一个索引数据'''
    print(li.get(0))  # aa
    '''4.2.获取非第一个索引数据'''
    print(li.get(2))  # cc

5.3.3 JavaScript代码实现

function Node(value) {
    this.value = value;
    this.nextNode = null;
}

Node.prototype.addNode = function (node) {
    if (null === this.nextNode) this.nextNode = node;
    else this.nextNode.addNode(node);
};

Node.prototype.removeNodeByValue = function (value) {
    let currentNode = this.nextNode;
    if (null === currentNode) return 0;
    if (value === currentNode.value) {
        this.nextNode = currentNode.nextNode;
        return -1;
    } else return this.nextNode.removeNodeByValue(value);
};

Node.prototype.removeNodeByIndex = function (index, firstNodeIndex = 0) {
    let currentNode = this.nextNode;
    let currentNodeIndex = ++firstNodeIndex;
    if (null === currentNode) return 0;
    if (currentNodeIndex === index) {
        this.nextNode = currentNode.nextNode;
        return -1;
    } else return this.nextNode.removeNodeByIndex(index, currentNodeIndex);
};

Node.prototype.updateNodeByValue = function (oldValue, newValue) {
    if (this.nextNode) {
        if (oldValue === this.nextNode.value) this.nextNode.value = newValue;
        else this.nextNode.updateNodeByValue(oldValue, newValue);
    }
};

Node.prototype.updateNodeByIndex = function (index, newValue, firstNodeIndex = 0) {
    if (this.nextNode) {
        let currentNodeIndex = ++firstNodeIndex;
        if (currentNodeIndex === index) this.nextNode.value = newValue;
        else this.nextNode.updateNodeByIndex(index, newValue, currentNodeIndex);
    }
};

Node.prototype.getNode = function (index, firstNodeIndex = 0) {
    if (this.nextNode) {
        let currentNodeIndex = ++firstNodeIndex;
        if (currentNodeIndex === index) return this.nextNode.value;
        else return this.nextNode.getNode(index, currentNodeIndex);
    }
};


function MySinglyLinkedList() {
    this.firstNode = null;
    this.nodeCount = 0;
}

MySinglyLinkedList.prototype.add = function (value) {
    let newNode = new Node(value);
    if (!this.firstNode) this.firstNode = newNode;
    else this.firstNode.addNode(newNode);
    this.nodeCount++;
};

MySinglyLinkedList.prototype.removeByValue = function (value) {
    if (this.firstNode) {
        if (value === this.firstNode.value) {
            this.firstNode = this.firstNode.nextNode;
            this.nodeCount--;
        } else this.nodeCount += this.firstNode.removeNodeByValue(value);
    }
};

MySinglyLinkedList.prototype.removeByIndex = function (index) {
    if (this.firstNode && 0 <= index && index < this.nodeCount) {
        if (0 === index) {
            this.firstNode = this.firstNode.nextNode;
            this.nodeCount--;
        } else this.nodeCount += this.firstNode.removeNodeByIndex(index);
    }
};

MySinglyLinkedList.prototype.updateByValue = function (oldValue, newValue) {
    if (this.firstNode) {
        if (oldValue === this.firstNode.value) this.firstNode.value = newValue;
        else this.firstNode.updateNodeByValue(oldValue, newValue);
    }
};

MySinglyLinkedList.prototype.updateByIndex = function (index, newValue) {
    if (this.firstNode && 0 <= index && index < this.nodeCount) {
        if (0 === index) this.firstNode.value = newValue;
        else this.firstNode.updateNodeByIndex(index, newValue);
    }
};

MySinglyLinkedList.prototype.get = function (index) {
    if (this.firstNode && 0 <= index && index < this.nodeCount) {
        if (0 === index) return this.firstNode.value;
        else return this.firstNode.getNode(index);
    }
};

MySinglyLinkedList.prototype.size = function () {
    return this.nodeCount;
};

MySinglyLinkedList.prototype.show = function () {
    let values = '[';
    let currentNode = this.firstNode;
    while (currentNode) {
        values += currentNode.value;
        currentNode = currentNode.nextNode;
        values += currentNode ? ', ' : '';
    }
    values += ']';
    console.log(values)
};


let list = new MySinglyLinkedList();

/*1.测试添加数据*/
["c", "b", "a", "aa", "bb", "cc", "a", "b", "c"].forEach(value => list.add(value));
list.show(); //[c, b, a, aa, bb, cc, a, b, c]

/*2.测试删除数据*/
/*2.1.索引方式删除第一个数据*/
list.removeByIndex(0);
list.show(); //[b, a, aa, bb, cc, a, b, c]
/*2.2.索引方式删除非第一个数据*/
list.removeByIndex(2);
list.show(); //[b, a, bb, cc, a, b, c]
/*2.3.节点值方式删除第一个数据*/
list.removeByValue("b");
list.show(); //[a, bb, cc, a, b, c]
/*2.4.节点值方式删除非第一个数据*/
list.removeByValue("c");
list.show(); //[a, bb, cc, a, b]

/*3.测试修改数据*/
/*3.1.索引方式修改第一个数据*/
list.updateByIndex(0, "aaa");
list.show(); //[aaa, bb, cc, a, b]
/*3.2.索引方式修改非第一个数据*/
list.updateByIndex(2, "ccc");
list.show(); //[aaa, bb, ccc, a, b]
/*3.3.节点值方式修改第一个数据*/
list.updateByValue("aaa", "aa");
list.show(); //[aa, bb, ccc, a, b]
/*3.4.节点值方式修改非第一个数据*/
list.updateByValue("ccc", "cc");
list.show(); //[aa, bb, cc, a, b]

/*4.测试获取数据*/
/*4.1.获取第一个数据*/
console.log(list.get(0)); //aa
/*4.2.获取非第一个数据*/
console.log(list.get(2)); //cc

16进制10进制.txt 32.txt asm.txt Crctable.txt C标志符命名源程序.txt erre.txt erre2.txt ff.txt for循环的.txt list.log N皇后问题回溯算法.txt ping.txt re.txt source.txt winsock2.txt ww.txt 万年历.txt 万年历的算法 .txt 乘方函数桃子猴.txt 乘法矩阵.txt 二分查找1.txt 二分查找2.txt 二叉排序树.txt 二叉树.txt 二叉树实例.txt 二进制数.txt 二进制数2.txt 余弦曲线.txt 余弦直线.txt 傻瓜递归.txt 冒泡排序.txt 冒泡法改进.txt 动态计算网络最长最短路线.txt 十五人排序.txt 单循环链表.txt 单词倒转.txt 单链表.txt 单链表1.txt 单链表2.txt 单链表倒序.txt 单链表的处理全集.txt 双链表正排序.txt 反出字符.txt 叠代整除.txt 各种排序法.txt 哈夫曼算法.txt 哈慢树.txt 四分砝码.txt 四塔1.txt 四塔2.txt 回文.txt 图.txt 圆周率.txt 多位阶乘.txt 多位阶乘2.txt 大加数.txt 大小倍约.txt 大整数.txt 字符串查找.txt 字符编辑.txt 字符编辑技术(插入和删除) .txt 完数.txt 定长串.txt 实例1.txt 实例2.txt 实例3.txt 小写数字转换成大写数字1.txt 小写数字转换成大写数字2.txt 小写数字转换成大写数字3.txt 小字库DIY-.txt 小字库DIY.txt 小孩分糖果.txt 小明买书.txt 小白鼠钻迷宫.txt 带头结点双链循环线性表.txt 平方根.txt 建树和遍历.txt 建立链表1.txt 扫描码.txt 挽救软盘.txt 换位递归.txt 排序法.txt 推箱子.txt 数字移动.txt 数据结构.txt 数据结构2.txt 数据结构3.txt 数组完全单元.txt 数组操作.txt 数组递归退出.txt 数组递归退出2.txt 文件加密.txt 文件复制.txt 文件连接.txt 无向图.txt 时间陷阱.txt 杨辉三角形.txt 栈单元加.txt 栈操作.txt 桃子猴.txt 桶排序.txt 检出错误.txt 检测鼠标.txt 汉字字模.txt 汉诺塔.txt 汉诺塔2.txt 灯塔问题.txt 猴子和桃.txt 百鸡百钱.txt 矩阵乘法动态规划.txt 矩阵转换.txt 硬币分法.txt 神经元模型.txt 穷举搜索法.txt 符号图形.txt 简单数据库.txt 简单计算器.txt 简单逆阵.txt 线性顺序存储结构.txt 线索化二叉树.txt 绘制圆.txt 编随机数.txt 网络最短路径Dijkstra算法.txt 自我复制.txt 节点.txt 苹果分法.txt 螺旋数组1.txt 螺旋数组2.txt 试题.txt 诺汉塔画图版.txt 读写文本文件.txt 货郎担分枝限界图形演示.txt 货郎担限界算法.txt 质因子.txt 输出自已.txt 迷宫.txt 迷宫问题.txt 逆波兰计算器.txt 逆矩阵.txt 逆阵.txt 递堆法.txt 递归桃猴.txt 递归车厢.txt 递推.txt 逻辑移动.txt 链串.txt 链栈.txt 链表十五人排序.txt 链表(递归).txt 链队列.txt 队列.txt 阶乘递归.txt 阿姆斯特朗数.txt 非递归.txt 顺序栈.txt 顺序表.txt 顺序队列.txt 骑士遍历1.txt 骑士遍历2.txt 骑士遍历回逆.txt 黑白.txt
16进制10进制.txt 32.txt asm.txt Crctable.txt C标志符命名源程序.txt erre.txt erre2.txt ff.txt for循环的.txt list.log N皇后问题回溯算法.txt ping.txt re.txt source.txt winsock2.txt ww.txt 万年历.txt 万年历的算法 .txt 乘方函数桃子猴.txt 乘法矩阵.txt 二分查找1.txt 二分查找2.txt 二叉排序树.txt 二叉树.txt 二叉树实例.txt 二进制数.txt 二进制数2.txt 余弦曲线.txt 余弦直线.txt 傻瓜递归.txt 冒泡排序.txt 冒泡法改进.txt 动态计算网络最长最短路线.txt 十五人排序.txt 单循环链表.txt 单词倒转.txt 单链表.txt 单链表1.txt 单链表2.txt 单链表倒序.txt 单链表的处理全集.txt 双链表正排序.txt 反出字符.txt 叠代整除.txt 各种排序法.txt 哈夫曼算法.txt 哈慢树.txt 四分砝码.txt 四塔1.txt 四塔2.txt 回文.txt 图.txt 圆周率.txt 多位阶乘.txt 多位阶乘2.txt 大加数.txt 大小倍约.txt 大整数.txt 字符串查找.txt 字符编辑.txt 字符编辑技术(插入和删除) .txt 完数.txt 定长串.txt 实例1.txt 实例2.txt 实例3.txt 小写数字转换成大写数字1.txt 小写数字转换成大写数字2.txt 小写数字转换成大写数字3.txt 小字库DIY-.txt 小字库DIY.txt 小孩分糖果.txt 小明买书.txt 小白鼠钻迷宫.txt 带头结点双链循环线性表.txt 平方根.txt 建树和遍历.txt 建立链表1.txt 扫描码.txt 挽救软盘.txt 换位递归.txt 排序法.txt 推箱子.txt 数字移动.txt 数据结构.txt 数据结构2.txt 数据结构3.txt 数组完全单元.txt 数组操作.txt 数组递归退出.txt 数组递归退出2.txt 文件加密.txt 文件复制.txt 文件连接.txt 无向图.txt 时间陷阱.txt 杨辉三角形.txt 栈单元加.txt 栈操作.txt 桃子猴.txt 桶排序.txt 检出错误.txt 检测鼠标.txt 汉字字模.txt 汉诺塔.txt 汉诺塔2.txt 灯塔问题.txt 猴子和桃.txt 百鸡百钱.txt 矩阵乘法动态规划.txt 矩阵转换.txt 硬币分法.txt 神经元模型.txt 穷举搜索法.txt 符号图形.txt 简单数据库.txt 简单计算器.txt 简单逆阵.txt 线性顺序存储结构.txt 线索化二叉树.txt 绘制圆.txt 编随机数.txt 网络最短路径Dijkstra算法.txt 自我复制.txt 节点.txt 苹果分法.txt 螺旋数组1.txt 螺旋数组2.txt 试题.txt 诺汉塔画图版.txt 读写文本文件.txt 货郎担分枝限界图形演示.txt 货郎担限界算法.txt 质因子.txt 输出自已.txt 迷宫.txt 迷宫问题.txt 逆波兰计算器.txt 逆矩阵.txt 逆阵.txt 递堆法.txt 递归桃猴.txt 递归车厢.txt 递推.txt 逻辑移动.txt 链串.txt 链栈.txt 链表十五人排序.txt 链表(递归).txt 链队列.txt 队列.txt 阶乘递归.txt 阿姆斯特朗数.txt 非递归.txt 顺序栈.txt 顺序表.txt 顺序队列.txt 骑士遍历1.txt 骑士遍历2.txt 骑士遍历回逆.txt 黑白.txt
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值