实践和项目:解决实际问题时,选择合适的数据结构和算法

news2024/11/25 7:00:28

文章目录

    • 选择合适的数据结构
      • 数组
      • 链表
      • 队列
      • 哈希表
    • 选择合适的算法
    • 实践和项目

在这里插入图片描述

🎉欢迎来到数据结构学习专栏~实践和项目:解决实际问题时,选择合适的数据结构和算法


  • ☆* o(≧▽≦)o *☆嗨~我是IT·陈寒🍹
  • ✨博客主页:IT·陈寒的博客
  • 🎈该系列文章专栏:数据结构学习
  • 📜其他专栏:Java学习路线 Java面试技巧 Java实战项目 AIGC人工智能 数据结构学习
  • 🍹文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏
  • 📜 欢迎大家关注! ❤️

在计算机科学中,数据结构和算法是两个非常重要的概念。数据结构是用来存储和组织数据的方式,而算法则是解决特定问题的步骤和操作。在实际应用中,选择合适的数据结构和算法对于提高程序的效率和解决实际问题的能力至关重要。
在这里插入图片描述

选择合适的数据结构

在计算机科学中,数据结构和算法是两个非常重要的概念。数据结构是用来存储和组织数据的方式,而算法则是解决特定问题的步骤和操作。在实际应用中,选择合适的数据结构和算法对于提高程序的效率和解决实际问题的能力至关重要。

数据结构的选择取决于具体的问题和场景。以下是一些常见的情况和对应的数据结构:

在这里插入图片描述

数组

数组是一种线性数据结构,它存储连续的元素,并可以通过索引直接访问。由于数组在内存中是连续存储的,因此访问数组元素的速度非常快。当需要快速访问元素时,数组是一种非常合适的数据结构。在这里插入图片描述

下面是一个使用数组的示例代码片段:

# 创建一个包含10个整数的数组
arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# 访问数组中的元素
print(arr[0])  # 输出:1
print(arr[5])  # 输出:6

链表

链表是一种非连续的数据结构,它由一系列节点组成,每个节点包含一个指向下一个节点的指针。链表适用于需要动态分配内存的情况,因为可以在运行时动态地添加或删除节点。
在这里插入图片描述

下面是一个使用链表的示例代码片段:

public class Node {
    int value;
    Node next;
    
    public Node(int value) {
        this.value = value;
        this.next = null;
    }
}

public class LinkedList {
    private Node head;
    
    public void add(int value) {
        Node newNode = new Node(value);
        if (head == null) {
            head = newNode;
        } else {
            Node current = head;
            while (current.next != null) {
                current = current.next;
            }
            current.next = newNode;
        }
    }
    
    public void remove(int value) {
        if (head == null) {
            return;
        }
        if (head.value == value) {
            head = head.next;
            return;
        }
        Node current = head;
        while (current.next != null && current.next.value != value) {
            current = current.next;
        }
        if (current.next != null) {
            current.next = current.next.next;
        }
    }
}

栈是一种后入先出(FILO)的数据结构。它遵循“先进后出”(LIFO)的原则,即最后一个插入的元素是第一个被删除的元素。栈适用于需要先入后出(FILO)的数据处理。例如,后入先出的队列就可以用栈来实现。
在这里插入图片描述

下面是一个使用栈的示例代码片段:

stack = []
stack.append(1)  # 插入元素1
stack.append(2)  # 插入元素2
print(stack.pop())  # 删除并返回元素2,输出:2
print(stack.pop())  # 删除并返回元素1,输出:1

队列

队列是一种先入先出(FIFO)的数据结构。它遵循“先进先出”(FIFO)的原则,即第一个插入的元素是第一个被删除的元素。队列适用于需要先入先出(FIFO)的数据处理。例如,操作系统的任务调度就可以用队列来实现。
在这里插入图片描述

下面是一个使用队列的示例代码片段:

queue = []
queue.append(1)  # 插入元素1
queue.append(2)  # 插入元素2
print(queue.pop(0))  # 删除并返回元素1,输出:1
print(queue.pop(0))  # 删除并返回元素2,输出:2

树是一种层次结构,由节点和连接节点的边组成。树中的每个节点可能有多个子节点,根节点没有父节点。树适用于需要层次结构和快速查找的情况。例如,文件系统就是用树来存储文件的。
在这里插入图片描述

下面是一个使用树的示例代码片段:

class TreeNode:
    def __init__(self, value):
        self.value = value
        self.children = []
        self.parent = None
        self.is_root = False
        self.is_leaf = False
        self.level = None
    
    def add_child(self, child):
        child.parent = self
        child.is_root = False
        child.level = self.level
        if not self.children:
        self.is_root = True
        child.parent = self
        self.children.append(child)

    def get_root(node):
        if node.is_root:
        return node
        else:
        return node.parent.get_root(node)

图是一种无限制的数据结构,由节点和连接节点的边组成。图中的节点和边可以带有权重或其他属性。图适用于需要表示复杂关系的情况。例如,社交网络就可以用图来表示。
在这里插入图片描述

下面是一个使用图的示例代码片段:

class Graph:
def __init__(self):
self.nodes = set()
self.edges = {}

def add_node(self, node):
self.nodes.add(node)
self.edges[node] = []

def add_edge(self, from_node, to_node, weight=1):
if from_node not in self.nodes or to_node not in self.nodes:
raise ValueError("Both nodes need to be in graph")
self.edges[from_node].append((to_node, weight))
self.edges[to_node].append((from_node, weight))

哈希表

哈希表是一种数据结构,它使用哈希函数将键映射到桶中,并在每个桶中存储相应的值。哈希表适用于需要快速查找键值对应关系的情况。例如,字典查找就可以用哈希表来实现。
在这里插入图片描述

下面是一个使用哈希表的示例代码片段:

class HashTable:
def __init__(self):
self.table = {}

def put(self, key, value):
hash_key = hash(key) % len(self.table)
bucket = self.table[hash_key]
for i, kv in enumerate(bucket):
if kv[0] == key:
bucket[i] = ((key, value))
return True
return False

选择合适的算法

算法的选择同样取决于具体的问题和场景。以下是一些常见的情况和对应的算法:
在这里插入图片描述

  1. 排序算法:适用于需要对大量数据进行有序处理的情况。例如,冒泡排序、快速排序、归并排序等。
  • 冒泡排序:这是一种简单的排序算法,它重复地遍历要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。遍历数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。
    在这里插入图片描述
def bubble_sort(arr):
    n = len(arr)
    for i in range(n):
        for j in range(0, n-i-1):
            if arr[j] > arr[j+1] :
                arr[j], arr[j+1] = arr[j+1], arr[j]
    return arr
  • 快速排序:这是一种分治的排序算法。它将一个数组分成两个子数组,然后对子数组进行递归排序。

在这里插入图片描述

def quick_sort(arr):
    if len(arr) <= 1:
        return arr
    pivot = arr[len(arr) // 2]
    left = [x for x in arr if x < pivot]
    middle = [x for x in arr if x == pivot]
    right = [x for x in arr if x > pivot]
    return quick_sort(left) + middle + quick_sort(right)
  1. 搜索算法:适用于需要在大量数据中查找特定元素的情况。例如,线性搜索、二分搜索等。
  • 线性搜索:这是一种简单的搜索算法,它遍历整个数组,比较每个元素与目标元素,如果匹配则返回该元素。
    在这里插入图片描述
def linear_search(arr, x):
    for i in range(len(arr)):
        if arr[i] == x:
            return i
    return -1
  • 二分搜索:这是一种高效的搜索算法,它只在排序的数组中搜索,并且搜索过程是对称的。它首先检查中间元素,如果中间元素是要搜索的元素,则搜索过程结束。如果中间元素大于要搜索的元素,则在数组的左半部分继续搜索。相反,如果中间元素小于要搜索的元素,则在数组的右半部分继续搜索。
    在这里插入图片描述
def binary_search(arr, low, high, x):
    if high >= low:
        mid = (high + low) // 2
        if arr[mid] == x:
            return mid
        elif arr[mid] > x:
            return binary_search(arr, low, mid - 1, x)
        else:
            return binary_search(arr, mid + 1, high, x)
    else:
        return -1
  1. 图算法:适用于需要处理图形结构的情况。例如,最短路径算法(Dijkstra、Bellman-Ford等)、最小生成树算法(Kruskal、Prim等)。
    在这里插入图片描述

这里以Dijkstra的最短路径算法为例:Dijkstra算法是一个用于解决给定节点到图中所有其他节点的最短路径问题的算法。它假设所有的边权重都是正数。

def dijkstra(graph, start_vertex):
    D = {v:float('infinity') for v in graph} 
    D[start_vertex] = 0 
    queue = [(0, start_vertex)] 
    while queue: 
        current_distance, current_vertex = min(queue, key=lambda x:x[0]) 
        queue.remove((current_distance, current_vertex)) 
        if current_distance > D[current_vertex]: 
            continue 
        for neighbor, weight in graph[current_vertex].items(): 
            old_distance = D[neighbor] 
            new_distance = current_distance + weight 
            if new_distance < oldDistance: 
                D[neighbor] = newDistance 
                queue.append((newDistance, neighbor)) 
    return D  #returns dictionary of shortest distances from start node to every other node in the graph. 
  1. 动态规划算法:适用于需要解决复杂问题,且问题的子问题也具有独立性时的情况。例如,背包问题、最长公共子序列问题等。
    以背包问题为例:背包问题是一种典型的动态规划问题,其目标是在给定背包容量和物品重量及价值的情况下,选择一系列物品装入背包以使得背包中的总价值最大。

在这里插入图片描述

def knapsack(weights, values, W):
    n = len(weights)
    dp = [[0 for _ in range(W+1)] for _ in range(n+1)]
    
    for i in range(1, n+1):
        for w in range(1, W+1):
            if weights[i-1] <= w:
                dp[i][w] = max(dp[i-1][w], dp[i-1][w-weights[i-1]] + values[i-1])
            else:
                dp[i][w] = dp[i-1][w]
                
    return dp[n][W]
  1. 分治算法:适用于可以将大问题分解为若干个小问题的情况。例如,归并排序、快速排序等。

这里以归并排序为例:归并排序是一种分治算法,它将一个数组分成两个子数组,然后对子数组进行递归排序,最后将两个已排序的子数组合并成一个已排序的数组。

在这里插入图片描述

def merge_sort(arr):
    if len(arr) <= 1:
        return arr
    mid = len(arr) // 2
    left = merge_sort(arr[:mid])
    right = merge_sort(arr[mid:])
    return merge(left, right)

def merge(left, right):
    result = []
    i = j = 0
    while i < len(left) and j < len(right):
        if left[i] <= right[j]:
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1
    result.extend(left[i:])
    result.extend(right[j:])
    return result
  1. 贪心算法:适用于问题的最优解可以通过一系列局部最优的选择来达到全局最优的情况。例如,霍夫曼编码、最小生成树等。
    这里以霍夫曼编码为例:霍夫曼编码是一种用于数据压缩的贪心算法。它通过为每个频繁出现的字符创建一个尽可能短的编码来工作。在编码过程中,每个字符的编码是根据前一个字符的编码来确定的。

在这里插入图片描述

class HuffmanNode:
    def __init__(self, freq, char=None):
        self.freq = freq 
        self.char = char 
        self.left = None 
        self.right = None 
        self.huff = None 
  
    def __cmp__(self, other): 
        if(other == None): 
            return -1 
        if(self.freq == other.freq): 
            return 0 
        elif(self.freq > other.freq): 
            return 1 
        else: 
            return -1 
  
def build_heap(arr): 
    n = len(arr)  
  
    for i in range(n//2 - 1, -1, -1): 
        heapify(arr, n, i) 
  
def heapify(arr, n, i): 
    smallest = i  
    left = 2*i + 1     
    right = 2*i + 2     
  
    if left < n and arr[smallest].freq > arr[left].freq: 
        smallest = left  
  
    if right < n and arr[smallest].freq < arr[right].freq: 
        smallest = right  
  
    if smallest != i: 
        arr[i], arr[smallest] = arr[smallest], arr[i]  # swap   
        heapify(arr, n, smallest)  # call heapify for the smallest element at root.  
  
def huffman_encode(arr): 
    arr_min = None  # to store the minimum frequency object  
    heap = []  # to store the heap  minimum at the root of heap.   //创建最小堆,根节点为最小值。   //将数组转化为最小堆。 build_heap(heap)  for item in arr:   heap.append(item)   build_heap(heap) //删除重复的元素 arr_min = heap[0] //将频率最小的元素移除 heap.remove(arr_min) //添加到 huffman tree 中 if arr_min.charif arr_min.char == None:
    arr_min = heap[0]
    heap.remove(arr_min)
    tree.add_node(arr_min)
else:
    tree.add_node(arr_min)
    heap.remove(arr_min)

# The function to print the binary tree.
def print_binary_tree(root):
    if root is not None:
        print_binary_tree(root.left)
        print(root.data, end=" ")
        print_binary_tree(root.right)

# The main function to find the Huffman编码 of a string.
def find_huffman_encoding(text):
    # Create a frequency table for all characters in the text.
    char_freq = {}
    for char in text:
        char_freq[char] = char_freq.get(char, 0) + 1

    # Create a priority queue to store the nodes of the Huffman tree.
    # The priority of a node is defined by the sum of the frequencies
    # of its two children.
    pq = []
    for char, freq in char_freq.items():
        pq.append((freq, char))
    heapq.heapify(pq)

    # Create an empty Huffman tree and add the nodes to it in a way
    # that maintains the property that the priority of a node is
    # defined by the sum of the frequencies of its two children.
    while len(pq) > 1:
        left = heapq.heappop(pq)
        right = heapq.heappop(pq)
        merge_node = HuffmanNode(left[0] + right[0], None)
        merge_node.left = HuffmanNode(left[0], left[1])
        merge_node.right = HuffmanNode(right[0], right[1])
        heapq.heappush(pq, merge_node)

    # The last element in the priority queue is the root of the Huffman tree.
    root = pq[-1]

    # Now, we can build the Huffman encoding by traversing the Huffman tree.
    huff_enc = []
    print_binary_tree(root)print("Huffman encoding for text: ")
huff_enc.reverse()  # reverse the list because the traversal is in reverse order.
print(huff_enc)

这个Python程序通过创建一个优先级队列(在Python中使用heapq实现)来存储每个字符的频率,然后通过合并频率最低的两个节点来构建霍夫曼树。一旦构建了霍夫曼树,就可以使用简单的遍历来为输入字符串生成霍夫曼编码。

实践和项目

选择合适的数据结构和算法是解决实际问题的重要步骤。以下是一些实践和项目,可以帮助你锻炼和应用所学知识:

  1. 参与开源项目:许多开源项目都涉及到复杂的数据结构和算法。参与这些项目的开发和维护,可以帮助你了解如何在实际应用中选择和实现数据结构和算法。

在这里插入图片描述

  1. 参加算法竞赛:许多大型的算法竞赛(如ACM、Google Code Jam等)都提供了大量的难题和挑战。通过解决这些难题,你可以更深入地理解和应用各种数据结构和算法。

在这里插入图片描述

  1. 构建自己的项目:选择一个实际问题,并尝试用数据结构和算法来解决它。例如,你可以尝试实现一个基于哈希表的字典查找系统,或者实现一个基于二分搜索的查找引擎。

在这里插入图片描述

总之,通过参与实践和项目,你可以更深入地了解各种数据结构和算法的应用场景和优劣性,从而提高你的程序设计和问题解决能力。


🧸结尾 ❤️ 感谢您的支持和鼓励! 😊🙏
📜您可能感兴趣的内容:

  • 【Java面试技巧】Java面试八股文 - 掌握面试必备知识(目录篇)
  • 【Java学习路线】2023年完整版Java学习路线图
  • 【AIGC人工智能】Chat GPT是什么,初学者怎么使用Chat GPT,需要注意些什么
  • 【Java实战项目】SpringBoot+SSM实战:打造高效便捷的企业级Java外卖订购系统
  • 【数据结构学习】从零起步:学习数据结构的完整路径

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/979055.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

水处理行业污水处理厂电能质量监测与治理系统解决方案-安科瑞黄安南

摘要&#xff1a;在水处理行业供配电系统中&#xff0c;涉及曝气风机、提升泵、污泥脱水设备等感性负荷设备&#xff0c;导致异步电动机产生较多无功功率和大量的谐波&#xff0c;使部分设备表现出轻载或不满载运行状况降低功率因数&#xff0c;以及谐波对配电系统、负载产生较…

leetcode 234. 回文链表

2023.9.5 本题先将链表的节点值移到数组中&#xff0c;再用双指针去判断该数组是否为回文的即可。 代码如下&#xff1a; /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* …

ST表(转载自其它博主)

文章目录 一、简介二、Leetcode题目补充1. 2023/9/6 更新 一、简介 ST表&#xff1a;https://zhuanlan.zhihu.com/p/123360481 二、Leetcode题目补充 1. 2023/9/6 更新 239. 滑动窗口最大值 class Solution {public int[] maxSlidingWindow(int[] nums, int k) {//记录数…

vue3项目,点击分页器,列表接口请求两次的问题

接手别人做的项目&#xff0c;出现了一个分页器bug&#xff0c;vue3element plus&#xff0c;记录一下。 点击分页器&#xff0c;却出现了调用两次列表接口的情况&#xff0c;并且第二次请求&#xff0c;分页器的pageNum自动变成1&#xff0c;这样就导致了分页器bug&#xff0…

Git 命令行查看仓库信息

目录 查看系统config ​编辑查看当前用户&#xff08;global&#xff09;配置 查看当前仓库配置信息 查看系统config git config --system --list 1 查看当前用户&#xff08;global&#xff09;配置 git config --global --list 1 查到的是email , name 等ssl签名信息&a…

不再产生火花:光耦合器继电器如何确保您的电路安全

近年来&#xff0c;对电子设备和电路的需求激增&#xff0c;推动了对更安全、更可靠的组件的需求。确保电路安全的关键元件之一是光耦继电器。这些不起眼的设备在保护电路和防止潜在危险情况&#xff08;例如火花和电气过载&#xff09;方面发挥着重要作用。 什么是光耦继电器…

Zoom正式发布类ChatGPT产品—AI Companion

9月6日&#xff0c;全球视频会议领导者Zoom在官网宣布&#xff0c;正式发布生成式AI助手——AI Companion。 AI Companion提供了与ChatGPT类似的功能&#xff0c;包括根据文本对话起草各种内容&#xff0c;自动生成会议摘要&#xff0c;自动回答会议相关问题等&#xff0c;以帮…

74HC138 , 38译码器

简介 74HC138D 是一种三通道输入、八通道输出译码器&#xff0c;主要应用于消费类电子产品

PMD 检查java代码:未使用的赋值(UnusedAssignment )

https://docs.pmd-code.org/latest/pmd_rules_java_bestpractices.html#unusedassignment 对一个变量赋了值&#xff0c;但这个值在被覆盖前从来没有用到&#xff0c;或者代码运行超出变量的作用范围还没有用到&#xff0c;就认为是未被使用的赋值。包含下面的情况&#xff1a…

一个产品级MCU菜单框架设计

分享一个用单色屏做的菜单框架。代码托管在github&#xff1a; https://github.com/wujique/stm32f407/tree/sw_arch 1、概述 本处所说的菜单是用在128*64这种小屏幕的菜单&#xff0c;例如下面这种&#xff0c;不是彩屏上的GUI。 2、菜单框架设计 作为一个底层驱动工程师&a…

Hadoop的分布式文件存储系统HDFS组件的使用

Hadoop的第一个核心组件&#xff1a;HDFS&#xff08;分布式文件存储系统&#xff09; 一、HDFS的组成1、NameNode2、DataNode3、SecondaryNameNode4、客户端&#xff1a;命令行/Java API 二、HDFS的基本使用1、命令行操作2、Java API操作 三、HDFS的工作流程问题&#xff08;H…

递归算法学习——N皇后问题,单词搜索

目录 ​编辑 一&#xff0c;N皇后问题 1.题意 2.解释 3.题目接口 4.解题思路及代码 二&#xff0c;单词搜索 1.题意 2.解释 3.题目接口 4.思路及代码 一&#xff0c;N皇后问题 1.题意 按照国际象棋的规则&#xff0c;皇后可以攻击与之处在同一行或同一列或同一斜线上…

阿里云服务器怎么退款?云服务器退款流程图

阿里云服务器如何退款&#xff1f;云服务器在哪申请退款&#xff1f;在用户中心订单管理中的退订管理中退款&#xff0c;阿里云百科分享阿里云服务器退款流程&#xff0c;包括申请退款入口、云服务器退款限制条件、退款多久到账等详细说明&#xff1a; 目录 阿里云服务器退款…

I/O系统:I/O设备,I/O接口,I/O端口的编址,I/O指令、通道指令,I/O控制方式 ,补充:中断

I/O&#xff1a;Input / Output&#xff0c;即输入/输出。 I/O系统一般由I/O硬件&#xff08;I/O设备&#xff0c;I/O接口&#xff0c;I/O总线等&#xff09;和I/O软件&#xff08;驱动程序&#xff0c;用户程序&#xff0c;管理程序&#xff0c;升级补丁等&#xff09;构成。…

基于sd的模特换装

这个领域的核心就是怎么把商品展示出来&#xff0c;商品本身不能发生变化&#xff0c;细节不能乱&#xff0c;模特换装或者虚拟换装&#xff0c;核心不在人&#xff0c;而在于商品&#xff0c;阿里塔玑这种核心在于怎么把平面的2D商品转成一个3D商品图&#xff0c;怎么让模特把…

蒙特卡洛方法使用原理解系-单位圆的面积计算

简介 蒙特卡洛也成为统计模拟方法&#xff0c;提出以概率统计理论为指导的一类非常重要的数值计算方法&#xff0c;是指使用随机数&#xff08;或者更常见的伪随机数&#xff09;来解决很多计算问题的方法。蒙特卡罗方法的名字来源于摩纳哥的一个城市蒙特卡罗&#xff0c;该城…

IIO驱动 Industrial I/O(正点原子笔记)

最近看见很多iio 驱动adc&#xff0c;赶紧找来学习一下。 传感器内部都会有ADC&#xff0c;传感器对外提供 IIC或者 SPI 接口&#xff0c;SOC 可以通过 IIC 或者 SPI 接口来获取到传感器内部的 ADC 数值&#xff0c;从而得到想要测量的结果。Linux 内核为了管理这些日益增多的…

恒运资本:港股内房股拉升 融创中国、中国恒大涨超30%

截至发稿&#xff0c;融创我国、我国恒大涨超30%&#xff0c;把戏年控股、天誉置业涨超20%。 9月6日&#xff0c;港股内地房地产板块拉升&#xff0c;截至发稿&#xff0c;融创我国、我国恒大涨超30%&#xff0c;把戏年控股、天誉置业涨超20%&#xff0c;佳兆业集团、富力地产…

springboot实战(六)之mybatis-plus代码自动生成器【重要】

目录 环境&#xff1a; 步骤&#xff1a; 1.添加依赖 2.配置代码 3.运行 测试 1.测试生成的service 1.1、service用法 2.分页查询 2.1、分页插件配置 2.2、测试 3.源码 环境&#xff1a; jdk:1.8 springboot版本&#xff1a;2.7.15 mybatis-plus版本&#xff1…

单片机-蜂鸣器

简介 蜂鸣器是一种一体化结构的电子讯响器&#xff0c;采用直流电压供电 蜂鸣器主要分为 压电式蜂鸣器 和 电磁式蜂鸣器 两 种类型。 压电式蜂鸣器 主要由多谐振荡器、压电蜂鸣片、阻抗匹配器及共鸣箱、外壳等组成。多谐振荡器由晶体管或集成电路构成&#xff0c;当接通电源后&…