链表编程问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了链表编程问题相关的知识,希望对你有一定的参考价值。

哪位高手帮我看看那里出了错啊!万分感谢!

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

struct node
int num;
int date;
struct node * next;
;

struct node * Create(int n);
struct node * SearchA(struct node * head,int num);
struct node * SearchB(struct node * head,int date);
struct node * Insert(struct node * head,struct node * stud);
struct node * Delete(struct node * head,int num);
void Print(struct node * head);

int main(void)

struct node * head,* p;
int n,num,date;
int size=sizeof(struct node);

printf(" Enter n: ");
scanf("%d",&n);
Create(n);
Print(head);

printf(" 输入序号 :");
scanf("%d",&num);
SearchA(head,num);

printf(" 输入值 :");
scanf("%d",&date);
SearchB(head,date);

printf("插入结点位置 :");
scanf("%d",num);
printf("插入结点数值 :");
scanf("%d",&date);
p=(struct node *)malloc(size);
p->num=num;
p->date=date;
head=Insert(head,p);
Print(head);

Delete(head,num);
printf("删除结点 :");
Print(head);

return 0;



/*新建链表*/
struct node * Create(int n)

struct node * head,* p;
int size=sizeof(struct node);
int num,number,date;

head=NULL;
printf(" Input num and date: \n");

for(number=1;number<=n;number++)
scanf("%d%d",&num,&date);
p=(struct node *)malloc(size);
p->num=num;
p->date=date;

head=Insert(head,p);



return head;


/*输入序号输出值*/
struct node * SearchA(struct node * head,int num)

struct node * ptr;

for(ptr=head;ptr;ptr=ptr->next)
if(ptr->num==num)
printf("输出值为 :",ptr->date);

return head;


/*输入值输出序号*/
struct node * SearchB(struct node * head,int date)

struct node * ptr;

for(ptr=head;ptr;ptr=ptr->next)
if(ptr->date==date)
printf("输出序号 :");


return head;


/*插入操作*/
struct node * Insert(struct node * head,struct node * stud)

struct node * ptr,* ptr1,* ptr2;

ptr2=head;
ptr=stud;
if(head==NULL)
head=ptr;
head->next=NULL;

else
while((ptr->num>ptr2->num)&&(ptr2->next!=NULL))
ptr1=ptr2;
ptr2=ptr2->next;

if(ptr->num<=ptr2->num)
if(head==ptr2) head=ptr;
else ptr1->next=ptr;
ptr->next=ptr2;

else
ptr2->next=ptr;
ptr->next=NULL;



return head;



/*删除操作*/
struct node * Delete(struct node * head,int num)

struct node * ptr1,* ptr2;

while(head!=NULL&&head->num==num)
ptr2=head;
head=head->next;
free(ptr2);

if(head==NULL)
return NULL;

ptr1=head;
ptr2=head->next;
while(ptr2!=NULL)
if(ptr2->num==num)
ptr1->next=ptr2->next;
free(ptr2);

else
ptr1=ptr2;
ptr2=ptr1->next;

return head;



/*遍历操作*/
void Print(struct node * head)

struct node * ptr;
if(head==NULL)
printf("\nNo Record\n");
return;

printf("输出链表 :");
for(ptr=head;ptr;ptr=ptr->next)
printf("%d ",ptr->date);

我根据你说的改了一下,还是不行,最好具体指出是哪的问题吧。谢了

//可以运行了,编的挺好的,小错见//

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

struct node
int num;
int date;
struct node * next;
;

struct node * Create(int n);
struct node * SearchA(struct node * head,int num);
struct node * SearchB(struct node * head,int date);
struct node * Insert(struct node * head,struct node * stud);
struct node * Delete(struct node * head,int num);
void Print(struct node * head);

int main(void)

struct node * head,* p;
int n,num,date;
int size=sizeof(struct node);

printf("Enter n: ");
scanf("%d",&n);
head=Create(n);//here
Print(head);

printf("输入序号 :");
scanf("%d",&num);
SearchA(head,num);

printf("输入值 :");
scanf("%d",&date);
SearchB(head,date);

printf("插入结点位置 :\n");
scanf("%d",&num);//missing &
printf("插入结点数值 :\n");
scanf("%d",&date);
p=(struct node *)malloc(size);
p->num=num;
p->date=date;
head=Insert(head,p);
Print(head);

head=Delete(head,num);//missing head=
printf("删除结点后 :\n");
Print(head);

return 0;



/*新建链表*/
struct node * Create(int n)

struct node * head,* p;
int size=sizeof(struct node);
int num,number,date;

head=NULL;
printf("Input num and date: \n");

for(number=1;number<=n;number++)
scanf("%d%d",&num,&date);
p=(struct node *)malloc(size);
p->num=num;
p->date=date;

head=Insert(head,p);



return head;


/*输入序号输出值*/
struct node * SearchA(struct node * head,int num)

struct node * ptr;

for(ptr=head;ptr;ptr=ptr->next)
if(ptr->num==num)

printf("输出值为 %d:\n",ptr->date);//missing %d
break;


if(ptr==NULL)
printf("该数据不存在\n");
return head;


/*输入值输出序号*/
struct node * SearchB(struct node * head,int date)

struct node * ptr;

for(ptr=head;ptr;ptr=ptr->next)
if(ptr->date==date)

printf("输出序号 %d:\n",ptr->num);//missing %d and ptr->num
break;


if(ptr==NULL)
printf("该序号不存在\n");
return head;


/*插入操作*/
struct node * Insert(struct node * head,struct node * stud)

struct node * ptr,* ptr1,* ptr2;

ptr2=head;
ptr=stud;
if(head==NULL)
head=ptr;
head->next=NULL;

else
while((ptr->num>ptr2->num)&&(ptr2->next!=NULL))
ptr1=ptr2;
ptr2=ptr2->next;

if(ptr->num<=ptr2->num)
if(head==ptr2) head=ptr;
else ptr1->next=ptr;
ptr->next=ptr2;

else
ptr2->next=ptr;
ptr->next=NULL;



return head;



/*删除操作*/
struct node * Delete(struct node * head,int num)

struct node * ptr1,* ptr2;

if(head==NULL)
return NULL;

if(head->num==num)

while(head!=NULL&&head->num==num)
ptr2=head;
head=head->next;
free(ptr2);


else

ptr1=head;
ptr2=head->next;
while(ptr2!=NULL)
if(ptr2->num==num)
ptr1->next=ptr2->next;
free(ptr2);

else
ptr1=ptr2;
ptr2=ptr1->next;


return head;



/*遍历操作*/
void Print(struct node * head)

struct node * ptr;
if(head==NULL)
printf("\nNo Record\n");
return;

printf("输出链表 :");
for(ptr=head;ptr;ptr=ptr->next)
printf("%d ",ptr->date);
printf("\n");
参考技术A 今天晚上没时间了,简单的看了一下,代码不规范,特别是在指针的使用上,指针在申明时就要付初始值的,不然就可能乱指,没有初始值就=NULL,在创建节点时,节点的next指针还是没有赋值,
虽然你在insert中赋值为NULL,但是在这之前是未知的。指针在没有时一定要赋值NULL,基本常识了。

以后再看吧!

C++并发编程:线程安全链表

问题描述

最近遇到这么一个问题,一个处理路径的函数,在多线程中被调用,我需要记录某个状态的路径,并在后续当再次处于某个状态时,从链表中将其取出。
为了满足这个需求,用来存储的数据结构要满足:

  1. 线程安全:防止在多线程中错误地对一个变量进行修改
  2. 便于查询
  3. 便于插入、删除
    最终想来选择了线程安全的链表,同时备选的队列,但队列不满足便于查询。

工程实践

作为一个“资深”程序员,我已经熟练掌握了从浩如烟海的百度中用CV大法来进行开发的武功。
所以,我很快地搜索到一段代码:

#include <iostream>

#include <memory>
#include <mutex>

template<typename T>   // 模板
class ThreadsafeList

    struct node   // 定义链表节点
    
        std::mutex m;   // 互斥体,用来保证线程安全,锁住节点
        std::shared_ptr<T> data;     // 数据,不必多讲
        std::unique_ptr<node> next;   // 指向下一个节点

        node() : next()

        node(T const& value) : data(std::make_shared<T>(value))    // 拷贝构造函数
        
    ;

    node head;     

public:
    ThreadsafeList()
    

    ~ThreadsafeList()
    
        remove_if([](T const&) return true; );
    

    ThreadsafeList(ThreadsafeList const& other) = delete;
    ThreadsafeList& operator=(ThreadsafeList const& other) = delete;

    void push_front(T const& value)      // 在头节点插入函数
    
        std::unique_ptr<node> new_node(new node(value));     // 创建一个新的节点
        std::lock_guard<std::mutex> lk(head.m);      // 锁
        new_node->next = std::move(head.next);     
        head.next = std::move(new_node);
    

    template<typename Function>
    void for_each(Function f)  // 遍历函数
    
        node* current = &head;
        std::unique_lock<std::mutex> lk(head.m);    // 对头节点上锁
        while (node* const next = current->next.get())
        
            std::unique_lock<std::mutex> next_lk(next->m);   // 上锁
            lk.unlock();                                                 // 对上个节点解锁
            f(*next->data);
            current = next;
            lk = std::move(next_lk);
        
    

    template<typename Predicate>
    std::shared_ptr<T> find_first_if(Predicate p)   // 查询函数
    
        node* current = &head;
        std::unique_lock<std::mutex> lk(head.m);
        while (node* const next = current->next.get())
        
            std::unique_lock<std::mutex> next_lk(next->m);
            lk.unlock();
            if (p(*next->data))
            
                return next->data;
            
            current = next;
            lk = std::move(next_lk);
        
        return std::shared_ptr<T>();
    

    template<typename Predicate>
    void remove_if(Predicate p)   // 删除函数
    
        node* current = &head;
        std::unique_lock<std::mutex> lk(head.m);
        while (node* const next = current->next.get())
        
            std::unique_lock<std::mutex> next_lk(next->m);
            if (p(*next->data))
            
                std::unique_ptr<node> old_next = std::move(current->next);
                current->next = std::move(next->next);
                next_lk.unlock();
            
            else
            
                lk.unlock();
                current = next;
                lk = std::move(next_lk);
            
        
    
;


int main()

    //简单函数功能测试
    ThreadsafeList<int> list;
    list.push_front(1);
    list.for_each([](const int& item) 
        std::cout << item << " ";
        );
    std::cout << std::endl;
    std::shared_ptr<int> ptr=list.find_first_if([](const int& item) return item == 1; );
    if (ptr.get()!=nullptr) 
        std::cout << *ptr << std::endl;
    


代码分析

在类ThreadSafeList中直接声明了一个结构体变量,比较少见,我也顺手查了一下。

这种方法和在面定义结构体,没什么区别,但是这里需要主义的是,在引用node节点的时候,没有public、private等,所以他是私有的。

class中默认的成员访问权限是private的,而struct中则是public的。

结构体中定义了一个互斥体,这就是保障线程安全的关键所在,每次要对节点进行操作的时候,就先上锁。

 struct node   // 定义链表节点
    
        std::mutex m;   // 互斥体,用来保证线程安全,锁住节点
        std::shared_ptr<T> data;     // 数据,不必多讲
        std::unique_ptr<node> next;   // 指向下一个节点

        node() : next()

        node(T const& value) : data(std::make_shared<T>(value))    // 拷贝构造函数
        
    ;

以查询函数为例:
std::unique_lockstd::mutex next_lk(next->m); 这是上锁操作,且使用的是unique_lock,这样就有俩种解锁方式,一种是unlock(),第二种就是在析构函数中解锁了,这也防止我们忘记解锁,这也满足了RAII原则。

    template<typename Predicate>
    std::shared_ptr<T> find_first_if(Predicate p)   // 查询函数
    
        node* current = &head;
        std::unique_lock<std::mutex> lk(head.m);
        while (node* const next = current->next.get())
        
            std::unique_lock<std::mutex> next_lk(next->m);
            lk.unlock();
            if (p(*next->data))
            
                return next->data;
            
            current = next;
            lk = std::move(next_lk);
        
        return std::shared_ptr<T>();
    

综上所述,这个类是满足我们选择“线程安全链表”的需求的

代码测试

写一个例子来测试一下。
这是我模拟我的需求写的一个简易例子,多线程对类中同一个数据链表进行读写访问,经过检测,没有出现问题!

// ThreadSafe.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <thread>
#include "thread_safe_list.hpp"
class ThreadSafeListTest

public:
    ThreadSafeListTest();
    ~ThreadSafeListTest();
    void thread_safe_list_test1();
    void thread_safe_list_test2();
    void thread_safe_list_test3();
private:
    ThreadsafeList<std::string> _name_list;
;

ThreadSafeListTest::ThreadSafeListTest()



ThreadSafeListTest::~ThreadSafeListTest()



void ThreadSafeListTest::thread_safe_list_test1()

    std::string target_name = "james";
    _name_list.push_front("harden");

    auto name = _name_list.find_first_if([target_name](const std::string& name) return target_name == name; );
    if (name != nullptr)
    
        _name_list.remove_if([target_name](const std::string& name) return target_name == name; );
    

void ThreadSafeListTest::thread_safe_list_test2()

    std::string target_name = "james";
    _name_list.push_front("curry");

    auto name = _name_list.find_first_if([target_name](const std::string& name) return target_name == name; );
    if (name != nullptr)
    
        _name_list.remove_if([target_name](const std::string& name) return target_name == name; );
    

void ThreadSafeListTest::thread_safe_list_test3()

    std::string target_name = "Fakejamesjames";
    _name_list.push_front("james");

    auto name = _name_list.find_first_if([target_name](const std::string& name) return target_name == name; );
    if (name != nullptr)
    
        _name_list.remove_if([target_name](const std::string& name) return target_name == name; );
    


void test1(ThreadSafeListTest& tslt)

    while (true)
    
        tslt.thread_safe_list_test1();
    

void test2(ThreadSafeListTest& tslt)

    while (true)
    
        tslt.thread_safe_list_test2();
    

void test3(ThreadSafeListTest& tslt)

    while (true)
    
        tslt.thread_safe_list_test3();
    

int main()

    ThreadSafeListTest test;
    std::thread t1(test1, std::ref(test));
    std::thread t2(test2, std::ref(test));
    std::thread t3(test3, std::ref(test));

    t1.join(); // join和主线程不分离,一起结束
    t2.join();
    t3.join();

    system("pause");
    return 0;



以上是关于链表编程问题的主要内容,如果未能解决你的问题,请参考以下文章

在 C 编程中将链表添加到另一个链表

C语言编程问题

纯函数式编程语言中的双向链表

C++并发编程:线程安全链表

C++并发编程:线程安全链表

C++并发编程:线程安全链表