字符串中单调递增连续子序列——Bash

本文介绍了一种求解字符串中最长连续递增子串的算法。通过一次遍历即可找出符合条件的最长子串,同时提供了具体的实现代码及运行结果。

该问题和求单调递增子序列有点像,但不一样。

其主要区别就是在于连不连续,如果不要求连续(单调递增子序列)在实现时的算法是动态规划,比较复杂。

本文描述的问题是子序列连续的问题,相比而言会简单很多,原理和求最大值是一样的。

 

具体描述为给定一个字符串,求一个子串,该子串满足:

1. 连续

2. 该子串递增

3. 是最长的单调连续递增的子串

 

例如:zxuhababcba

结果:abc

 

 

代码如下: 

 

#!/bin/bash

## the input str for test
inputStr="zxuhababcba";
strLength=${#inputStr};

## record the max monotone increasing sub str
maxSubStrLength=0;
maxStartPos=0;
## record the position of current monotone increasing sub str
currentStartPos=0;

## find the result
for((i=1;i<strLength;i++))
do
    j=$((i-1));
    if [ "${inputStr:$i:1}" \< "${inputStr:$j:1}"  ]; then
        currentSubStrLength=$((i-currentStartPos));
        if [ $currentSubStrLength -gt $maxSubStrLength  ]; then
            maxSubStrLength=$currentSubStrLength;
            maxStartPos=$currentStartPos;
        fi
            currentStartPos=$i;
    fi
done

lastLength=$((strLength-currentStartPos));
if [ $lastLength -gt $maxSubStrLength ]; then
    maxSubStrLength=$lastLength;
    maxStartPos=$currentStartPos;
fi

echo    "original string is    : ${inputStr}";
echo -n "max increasing subStr : "
for((i=0;i<$maxStartPos;i++))
do
    echo -n " ";
done
echo "${inputStr:$maxStartPos:$maxSubStrLength}";

 

 

 

在扫描过程中,记下目前为止最长的单调递增序列的开始和长度,并在当扫描中出现“拐弯”情况时,将新的递增子序列与当前记录中的最长单调递增子序列比较。

 

运行结果为:

 

 

 

该方法和给定一个数组,求数组中最大元素的方法是一回事。

 

此外,如果你想求最长单调递减子序列,则只需要改变上述代码中的一个字符就可以了,你知道是哪个吗?哈哈^_^

 

 欢迎来拍!!!

非常好的问题!我们来深入分析 **Linux 内核中,新创建的网络接口(`net_device`)是如何将其 `ifindex` 插入到哈希桶 `dev_index_head[]` 中的**,并定位关键源码位置。 --- ### ✅ 结论先行 > 新创建的 `net_device` 会通过函数 `dev_hash_insert()` 将其插入两个哈希表: > > - `dev_name_head[]`:按名称(如 `eth0`)哈希 > - `dev_index_head[]`:按 `ifindex` 哈希 > > 插入操作发生在设备注册阶段(`register_netdevice()`),使用 **链表头插法(prepend)**,即插入对应哈希桶的链表头部。 > > 源码路径:`net/core/dev.c` --- ## 🔍 核心机制详解 ### 1. `ifindex` 的分配 当调用 `alloc_netdev()` 或类似函数创建设备时,`ifindex` 初始为 0。 真正的分配发生在注册过程中: ```c int register_netdevice(struct net_device *dev) ``` 在该函数中调用: ```c if (!dev->ifindex) dev->ifindex = dev_new_index(net); ``` 👉 `dev_new_index()` 分配一个全局唯一的、单调递增的整数作为 `ifindex`。 --- ### 2. 哈希结构定义 内核维护两个哈希数组用于快速查找: ```c struct hlist_head dev_name_head[NETDEV_HASHENTRIES]; struct hlist_head dev_index_head[NETDEV_HASHENTRIES]; ``` - `dev_name_head`: 以设备名(字符串)为键进行哈希 - `dev_index_head`: 以 `ifindex` 为键进行哈希 它们都位于 `struct net` 结构体中(每个网络命名空间一份)。 --- ### 3. 关键函数:`dev_hash_insert()` 这是真正执行插入哈希桶的函数。 #### 📍 源码位置: ``` net/core/dev.c ``` #### 🧩 函数原型: ```c static int dev_hash_insert(struct net_device *dev, unsigned int hash) ``` #### 📄 实现片段(简化版): ```c static int dev_hash_insert(struct net_device *dev, unsigned int hash) { struct hlist_head *head = &pnet(dev_net(dev))->dev_name_head[hash]; struct hlist_head *index_head = &pnet(dev_net(dev))->dev_index_head[dev->ifindex & ((1 << NETDEV_HASHBITS) - 1)]; hlist_add_head(&dev->name_hlist, head); // 插入 name 哈希 hlist_add_head(&dev->index_hlist, index_head); // 插入 index 哈希 return 0; } ``` 📌 注意: - `dev->name_hlist` 和 `dev->index_hlist` 是嵌入在 `struct net_device` 中的链表节点。 - 使用 `hlist_add_head()` 表示 **头插法** —— 新设备插入链表最前面。 --- ### 4. 调用时机:`register_netdevice()` 中完成插入 在 `register_netdevice()` 函数末尾附近: ```c err = dev_hash_insert(dev, hash); if (err) goto err_undo; ``` 这意味着: > 只有成功通过所有检查后,才会将设备加入哈希表。 --- ### 5. 哈希函数计算方式 #### 对于 `dev_index_head`: ```c index_head = &dev_index_head[dev->ifindex & ((1 << NETDEV_HASHBITS) - 1)] ``` 其中: - `NETDEV_HASHBITS` 通常为 8 - 所以掩码是 `(1<<8)-1 = 255` - 即:`bucket = ifindex & 0xFF` 这等价于 `ifindex % 256`,但更快。 ✅ 因此 `ifindex=1`, `257`, `513` 都会落在同一个桶里(冲突处理靠链表) --- ### 🧪 示例说明 假设: - 当前要注册设备 `eth0`,系统自动分配 `ifindex = 2` - `NETDEV_HASHBITS = 8` → `bucket = 2 & 255 = 2` 那么: ```c hlist_add_head(&dev->index_hlist, &dev_index_head[2]); ``` 新设备成为 `dev_index_head[2]` 链表的第一个元素。 如果后续再有一个 `ifindex=258` 的设备(比如虚拟接口),也会进入 bucket 2,继续头插。 --- ### 🔎 查看源码建议方式 你可以通过以下任一方式查看真实源码: #### 方式 1:在线浏览 Elixir 🔗 [https://elixir.bootlin.com/linux/latest/source/net/core/dev.c#L2000](https://elixir.bootlin.com/linux/latest/source/net/core/dev.c#L2000) 搜索关键词: - `dev_hash_insert` - `dev_index_head` - `register_netdevice` #### 方式 2:本地克隆 Linux 内核 ```bash git clone https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git cd linux grep -n "dev_hash_insert" net/core/dev.c ``` 你会看到完整的插入逻辑。 --- ### ⚙️ 数据结构关系图解 ```text struct net { struct hlist_head dev_name_head[256]; ← 按名字哈希 struct hlist_head dev_index_head[256]; ← 按 ifindex 哈希 } struct net_device { ... struct hlist_node name_hlist; // 连接到 dev_name_head[bucket] struct hlist_node index_hlist; // 连接到 dev_index_head[bucket] int ifindex; // 如 1, 2, 3... char name[IFNAMSIZ]; // 如 "lo", "eth0" } ``` 插入后: ```text dev_index_head[2]: ┌─────────────┐ │ eth0 │ ← ifindex=258 ├─────────────┤ │ eth0 │ ← ifindex=2 └─────────────┘ ``` 👉 头插导致高 `ifindex` 可能在低 `ifindex` 前面(桶内逆序) --- ### ✅ 总结 | 项目 | 内容 | |------|------| | 插入函数 | `dev_hash_insert()` | | 源码文件 | `net/core/dev.c` | | 哈希桶数组 | `dev_index_head[NETDEV_HASHENTRIES]` | | 哈希算法 | `bucket = ifindex & ((1<<NETDEV_HASHBITS)-1)` | | 插入方式 | `hlist_add_head()` → 头插法 | | 是否有序 | 桶内逆序(最新插入在前),整体趋势仍近似升序 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值