简体   繁体   中英

Printing relations between members

I've a university project in which I've to print the relations between students in different classes level by level. The idea is if we have John and Kris studying in the same class they are friends of first level, if Kris studies with Math in same class then John and Math are friends of second level. I researched the problem and I found algorithms like this , but my main problem is that I use objects as input data :

<?php
class Student {

 private $id = null;
 private $classes = [];

 public function __construct($id) {
   $this->id = $id;
 }

 public function getId() {
   return $this->id;
 }

 public function getClasses() {
   return $this->classes;
 }

 public function addClass(UClass $class) {
   array_push($this->classes, $class);
 }

}

class UClass {

 private $id = null;
 private $students= [];

 public function __construct($id) {
   $this->id = $id;
 }

 public function getId() {
   return $this->id;
 }

 public function getStudents() {
   return $this->students;
 }

 public function addStudent(Student $student) {
   array_push($this->students, $student);
   $student->addClass($this);
 }

}

function getRelations(Student $start_student, &$tree = array(), $level = 2, &$visited) {
 foreach ($start_student>Classes() as $class) {    
   foreach ($class->Students() as $student) {
     if($start_student->getId() != $student->getId() && !is_int(array_search($student->getId(), $visited))) {
         $tree[$level][] = $student->getId();
         array_push($visited, $student->getId());
         getRelations($student, $tree, $level+1, $visited); 
     }
   }
 }
}

$class = new UClass(1);
$class2 = new UClass(2);
$class3 = new UClass(3);

$student = new Student(1);
$student2 = new Student(2);
$student3 = new Student(3);
$student4 = new Student(4);
$student5 = new Student(5);
$student6 = new Student(6);

$class->addStudent($student);
$class->addStudent($student2);
$class->addStudent($student4);

$class2->addStudentr($student2);
$class2->addStudent($student4);
$class2->addStudent($student5);

$class3->addStudent($student4);
$class3->addStudent($student5);
$class3->addStudent($student6);

$tree[1][] = $student->getId();
$visited = array($student->getId());
getRelations($student, $tree, 2, $visited);
print_r($tree);

I'm stuck at writing getRelations() function that should create an array that is something like

Array ( [1] => Array ( [0] => 1 ) [2] => Array ( [0] => 2 [1] => 4 ) [3] => Array ( [0] => 5 [1] => 6 ) ) 

but I can't get the recursion right(or probably the whole algorithm). Any help will be greatly appreciated.

I come up with that function(not sure if it's the best solution, but it works with the class objects)

function print_students(Student $start_student, &$tree = array(), $lvl = 1) {
  if (!$start_student) {
    return;
  }
  $tree[$lvl][] = $start_student->getId();
  $q = array();
  array_push($q, $start_student);
  $visited = array($start_student->getId());

  while (count($q)) {
    $lvl++;
    $lvl_students = array();
    foreach ($q as $current_student) {
      foreach ($current_student->getClasses() as $class) {
        foreach ($class->getStudents() as $student) {
          if (!is_int(array_search($student->getId(), $visited))) {
            array_push($lvl_students, $student);
            array_push($visited, $student->getId());
            $tree[$lvl][] = $student->getId();
          }
        }
      }
    }
    $q = $lvl_students;
  }
}

The logic in your recursive procedure is not correct. Example:

Say you enter the procedure for some level A and there are actually 2 students to be found for a connection at that level.

You handle the first, assign the correct level A, mark him as "visited".

Then, before getting to the second, you process level A+1 for the first student. Somewhere in his "chain" you may also find the second student that was waiting to get handled at level A. However, he now gets assigned some higher level A+n, and is then marked as visited.

Next, when the recursion for student1 is finished, you continue with the second. However, he has already been "visited"...

(By the way, I do not quite understand (but my php is weak...) why your first invocation of GetRelations specifies level=2.)

Anyway, to get your logic right there's no need for recursion.

Add a property "level" to each student. Put all students also in an overall collection "population".

Then, for a chosen "startStudent", give himself level=0, all other students level=-1.

Iterate levels and try to fill in friendship levels until there's nothing left to do. My php is virtually non-existent, so I try some pseudo-code.

  for(int level=0; ; level++) // no terminating condition here
   {
      int countHandled = 0;
      for each (student in population.students)
      {
        if (student.level==level)
        {
          for each (class in student.classes)
          {
            for each (student in class.students)
            {
              if(student.level==-1)
              {
                student.level = level+1;
                countHandled++;
              }
            }
          }
        }
      }
      if(countHandled==0)
        break;
    }

Hope this helps you out. Of course, you still have to fill in the tree/print stuff; my contribution only addresses the logic of assigning levels correctly.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM