alg : 单向链表回环的判断 on drv

单向链表回环的判断可以用步长法

这个实现 : 选择单向链表中的任一节点, 遍历单向链表, 判断是否能回到同一节点.


demo:

    /// 建立链表
    CreateList(&pNode, 6);  ///< 建立拥有N个节点的单向链表
    ShowList(&pNode);

    /// 判断单向链表是否回环
    DbgPrint("List loop is %ws\n", (TRUE == FindLoop(pNode)) ? L"TRUE" : L"FALSE");

    /// 释放链表
    RemoveList(&pNode);
    ShowList(&pNode);

实现:

/// @file           Function.h
/// @brief          功能的实现

#ifndef __FUNCTION_H__
#define __FUNCTION_H__

#include <ntddk.h>

typedef struct _node
{
    int data;
    struct _node *next;
} NODE,*PNODE;

///< 外部接口
int FindLoop(NODE * head);

/// 内部接口
void CreateList(PNODE * ppNode, size_t nListSize);
void RemoveList(PNODE * ppNode);
void ShowList(PNODE * ppNode);
BOOLEAN IsListLoop(PNODE * ppNode);

#endif

/// @file           Function.c
/// @brief          功能的实现

#include "Function.h"

void CreateList(PNODE * ppNode, size_t nListSize)
{
    PNODE   pNodeHead   =   NULL;
    PNODE   pNodeCur    =   NULL;
    size_t  nIndex      =   0;

    if ((NULL == ppNode) || (NULL != *ppNode) || (nListSize < 1))
    {
        return;
    }

    pNodeHead = (PNODE)ExAllocatePool(NonPagedPool, sizeof(NODE));
    pNodeHead->data = 0;
    pNodeHead->next = NULL;
    *ppNode = pNodeHead;

    pNodeCur = pNodeHead;
    for (nIndex = 1; nIndex < nListSize; nIndex++)
    {
        pNodeCur->next = (PNODE)ExAllocatePool(NonPagedPool, sizeof(NODE));
        
        pNodeCur = pNodeCur->next;
        pNodeCur->data = nIndex;
        pNodeCur->next = NULL;
    }

    pNodeCur->next = pNodeHead; ///< 形成单链表回环
}

void ShowList(PNODE * ppNode)
{
    PNODE   pNodeCur    =   NULL;
    PNODE   pNodeHead   =   NULL;

    if ((NULL == ppNode) || (NULL == *ppNode))
    {
        DbgPrint("ppNode is invalid\n");
        return;
    }

    pNodeHead = *ppNode;
    DbgPrint("pNodeHead = 0x%p, pNodeHead->data = 0x%x, pNodeHead->next = 0x%p\n", 
        pNodeHead, pNodeHead->data, pNodeHead->next);

    pNodeCur = pNodeHead->next;
    while ((NULL != pNodeCur) && (pNodeCur != pNodeHead))
    {
        DbgPrint("pNodeCur = 0x%p, pNodeCur->data = 0x%x, pNodeCur->next = 0x%p\n",
            pNodeCur, pNodeCur->data, pNodeCur->next);
        pNodeCur = pNodeCur->next;
    }
}

void RemoveList(PNODE * ppNode)
{
    PNODE   pNodeHead   =   NULL;
    PNODE   pNodeCur    =   NULL;
    PNODE   pNodeNext   =   NULL;

    if ((NULL == ppNode) || (NULL == *ppNode))
    {
        return;
    }

    pNodeHead = *ppNode;

    /// 释放头节点之外的数据
    pNodeCur = pNodeHead->next;
    while ((NULL != pNodeCur) && (pNodeCur != pNodeHead))
    {
        pNodeNext = pNodeCur->next;
        ExFreePool(pNodeCur);
        pNodeCur = pNodeNext;
    }

    /// 释放头节点
    ExFreePool(pNodeHead);
    *ppNode = NULL;
}

BOOLEAN IsListLoop(PNODE * ppNode)
{
    BOOLEAN bFind       =   FALSE;
    PNODE   pNodeCur    =   NULL;
    PNODE   pNodeHead   =   NULL;

    if ((NULL == ppNode) || (NULL == *ppNode))
    {
        DbgPrint("ppNode is invalid\n");
        return FALSE;
    }

    pNodeHead = *ppNode;
    pNodeCur = pNodeHead->next;
    while (NULL != pNodeCur)
    {
        if (pNodeCur == pNodeHead)
        {
            bFind = TRUE;
            break;
        }

        pNodeCur = pNodeCur->next;
    }

    return bFind;
}

int FindLoop(NODE * head)
{
    if (NULL == head)
    {
        return FALSE;
    }

    return IsListLoop(&head);
}

/// @file           sys.c
/// @brief          驱动主程序

#include <ntddk.h>
#include "Function.h"

#define MODULE_NAME         L"DrvDemo"
#define DRIVER_NAME         MODULE_NAME L".sys"
#define DEVICE_NAME_GLOBAL  L"\\\\.\\" MODULE_NAME
#define DEVICE_NAME         L"\\device\\" MODULE_NAME
#define LINK_NAME           L"\\dosDevices\\" MODULE_NAME

NTSTATUS DispatchCommon(PDEVICE_OBJECT pDeviceObject, PIRP pIrp);
VOID DriverUnload(PDRIVER_OBJECT pDriverObject);

NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, 
                     IN PUNICODE_STRING pRegPath)
{
    size_t          nIndex  =   0;
    NTSTATUS        ntStatus = STATUS_SUCCESS;
    PDEVICE_OBJECT  pDeviceObject = NULL;

    UNICODE_STRING  ustrDeviceName = {0};
    UNICODE_STRING  ustrLinkName = {0};

    PNODE   pNode    =   NULL;

    DbgPrint(">> DriverEntry\r\n");

    RtlInitUnicodeString(&ustrDeviceName, DEVICE_NAME);
    RtlInitUnicodeString(&ustrLinkName, LINK_NAME);

    ntStatus = IoCreateDevice(
        pDriverObject, 
        0, 
        &ustrDeviceName, 
        FILE_DEVICE_UNKNOWN, 
        0, 
        FALSE, 
        &pDeviceObject);
    if (!NT_SUCCESS(ntStatus))
    {
        DbgPrint("<< DriverEntry : error IoCreateDevice\r\n");
        return ntStatus;
    }

    pDeviceObject->Flags |= DO_BUFFERED_IO;
    ntStatus = IoCreateSymbolicLink(
        &ustrLinkName, 
        &ustrDeviceName);
    if (!NT_SUCCESS(ntStatus))
    {
        DbgPrint("<< DriverEntry : error IoDeleteDevice\r\n");
        IoDeleteDevice(pDeviceObject);
        return ntStatus;
    }

    for(nIndex = 0; nIndex < IRP_MJ_MAXIMUM_FUNCTION; nIndex++)
    {
        pDriverObject->MajorFunction[nIndex] = DispatchCommon;
    }

    pDriverObject->DriverUnload = DriverUnload;

    /// 建立链表
    CreateList(&pNode, 6);  ///< 建立拥有N个节点的单向链表
    ShowList(&pNode);

    /// 判断单向链表是否回环
    DbgPrint("List loop is %ws\n", (TRUE == FindLoop(pNode)) ? L"TRUE" : L"FALSE");

    /// 释放链表
    RemoveList(&pNode);
    ShowList(&pNode);

    DbgPrint("<< DriverEntry\r\n");

    return STATUS_SUCCESS;
}

VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
    UNICODE_STRING ustrLinkName = {0};

    DbgPrint(">> DriverUnload\r\n");

    RtlInitUnicodeString(&ustrLinkName, LINK_NAME);
    IoDeleteDevice(pDriverObject->DeviceObject);
    IoDeleteSymbolicLink(&ustrLinkName);

    DbgPrint("<< DriverUnload\r\n");
}

NTSTATUS DispatchCommon(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
    pIrp->IoStatus.Information = 0;
    pIrp->IoStatus.Status = STATUS_SUCCESS;

    IoCompleteRequest(pIrp, IO_NO_INCREMENT);

    return STATUS_SUCCESS;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值