PHP数据结构与算法实现

二分查找

//二分查找
$data = array(4,6,7,8,14,55,67,145,218,237,284);
function binarySearch($data, $num){
    $count = count($data);
    $high = $count - 1;
    $low = 0;
    while ($low <= $high){
        $mid = floor(($high + $low) / 2);
        //$mid = floor($low + ($num - $data[$low]) / ($data[$high] - $data[$low]) * ($high - $low));//插值查找
        if($num == $data[$mid]){
            return $mid;
        }elseif ($num > $data[$mid]){
            $low = $mid + 1;
        }else{
            $high = $mid -1;
        }
    }
    return false;
}
$res = binarySearch($data, 4);
var_dump($res); //1

插值查找(二分查找优化)
首先考虑一个新问题,为什么一定要是折半,而不是折四分之一或者折更多呢?
打个比方,在英文字典里面查“apple”,你下意识翻开字典是翻前面的书页还是后面的书页呢?如果再让你查“zoo”,你又怎么查?很显然,这里你绝对不会是从中间开始查起,而是有一定目的的往前或往后翻。
同样的,比如要在取值范围1 ~ 10000 之间 100 个元素从小到大均匀分布的数组中查找5, 我们自然会考虑从数组下标较小的开始查找。
经过以上分析,折半查找这种查找方式,还是有改进空间的,并不一定是折半的!
mid = (low+high)/ 2, 即 mid = low + 1/2 * (high - low);
改进为下面的计算机方案(不知道具体过程):mid = low + (key - a[low]) / (a[high] - a[low]) * (high - low),也就是将上述的比例参数1/2改进了,根据关键字在整个有序表中所处的位置,让mid值的变化更靠近关键字key,这样也就间接地减少了比较次数。

分析:从时间复杂度上来看,它也是o(n),但是对于表长较大,而关键字分布又比较均匀的查找表来说,插值查找算法的平均性能比折半查找要好的多。反之,数组中如果分布非常不均匀,那么差值查找未必是很合适的选择。

二叉搜索树

<?php
class node{
	public $value;
	public $left;
	public $right;
	public $parent;

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

class searchtree{
	public $root = null;
	public $size = 0;
	public $depth = 0;

	public function __construct($value){
		$this->root = new node($value);
		$this->size++;
		$this->depth++;
	}

	public function addnode($array){
		foreach ($array as $key=> $value) {
			$current = $this->root;
			$parent = null;
			$currentdepth = 1;

			while($current !== null){
				$parent = $current;
				if($current->value == $value){
					continue 2;
				}
				elseif($current->value > $value){
					$current = $current->left;
				}else{
					$current = $current->right;
				}
				$currentdepth++;
			}

			$node = new node($value);
			$node->parent = $parent;
			if($parent->value > $value){
				$parent->left = $node;
			}else{
				$parent->right = $node;
			}
			if($this->depth < $currentdepth){
				$this->depth++;
			}
			$this->size++;
		}
		return true;
	}

	public function successor($node){
		if ($node->right !== null) {
			$current = $node->right;
			while($current->left !== null){
				$current = $current->left;
			}
        	return $current;
	    }
	    $parent = $node->parent;
	    while ($parent !== null && $node = $parent->right) {
	        $node = $parent;
	        $parent = $parent->parent;
	    }
    	return $parent;
	}

	public function delnode($value) {
		$node = $this->search($value);
		if ($node->left === null || $node->right === null) { 
			#如果待删除结点无子节点或只有一个子节点,则c = dnode
		    $current = $node;
		} else { 
			#如果待删除结点有两个子节点,c置为dnode的直接后继,以待最后将待删除结点的值换为其后继的值
		    $current = $this->successor($node);
		}

		//print_r($current->value);exit;

		if ($current->left !== null) {
		    $s = $current->left;
		} else {
		    $s = $current->right;
		}
		if ($s !== null) { #将c的子节点的父母结点置为c的父母结点,此处c只可能有1个子节点,因为如果c有两个子节点,则c不可能是dnode的直接后继
		    $s->parent = $current->parent;
		}
		if ($current->parent === null) { #如果c的父母为空,说明c=dnode是根节点,删除根节点后直接将根节点置为根节点的子节点,此处dnode是根节点,且拥有两个子节点,则c是dnode的后继结点,c的父母就不会为空,就不会进入这个if
		    $this->root = $s;
		} else if ($current == $current->parent->left) { #如果c是其父节点的左右子节点,则将c父母的左右子节点置为c的左右子节点
		    $current->parent->left = $s;
		} else {
		    $current->parent->right = $s;
		}
		#如果c!=dnode,说明c是dnode的后继结点,交换c和dnode的key值
		if ($current != $node) {
		    $node->value = $current->value;
		}
		#返回成功
		return true;
	}
	public function search($value){
		$current = $this->root;
		while($current !== null){
			if($current->value == $value){
				return $current;
			}
			elseif($current->value > $value){
				$current = $current->left;
			}else{
				$current = $current->right;
			}
		}
		return false;
	}
}
$tree = new searchtree(300);
$tree->addnode(array(124,360,250,110,260,270,160,350,370,320,352));
$tree->delnode(300);
print_r($tree);

?>

单链表

<?php
//单个节点
class node {
	//初始化变量,包括存储的内容 和 下一个数据的指针
	public $id = 0;
	public $data = '';
	public $next = null;

	//构造函数,设置存储内容的数据
	public function __construct($id,$nodedata){
		$this->id = $id;
		$this->data = $nodedata;
	}
}

class singleLink {
	public $head = '';
	public $size = 0;

	public function insert($id,$value,$prenodeid = 0){
		$node = new node($id,$value);
		//空链表,直接添加
		if ($this->size == 0){
			$this->head = $node;
		} elseif ($prenodeid == 0) {
			//如果不是空链表,且并没有指定在某一个节点前添加
			//则在当前节点前添加
			$node->next = $this->head;
			$this->head = $node;
		} else {
			//在某一节点后添加新节点
			$cruntnode = $this->head;
			while($cruntnode->next != null ){
				if($cruntnode->next->id == $prenodeid){
					$node->next = $cruntnode->next;
					$cruntnode->next = $node;
					break;
				}
				$cruntnode = $cruntnode->next;
			}
		}
		$this->size++;
		return $this;
	}

	public function edit($id,$value){
		$flag = false;
		$current = $this->head;
		while(@$current->id !=null){
			if($current->id == $id){
				$current->data = $value;
				$flag = true; 
				break;
			} 
			$current = $current->next;
		}
		return $flag;
	}

	public function get($id=0){
		$current = $this->head;
		while(@$current->id !=null){
			if($id !=0 && $current->id==$id){
				$node = $current;
				break;
			} else {
				$node[] = array($current->id,$current->data);
			}
			$current = $current->next;
		}
		return $node;
	}

	public function sort(){
		
	}

	public function delete($id){
		$flag = false;
		$current = $this->head;
		while(@$current->id !=null){
			if($current->next->id == $id){
				$current->next = $current->next->next;
				$this->size--;
				$flag = true; 
				break;
			} 
			$current = $current->next;
		}
		return $flag;
	}

}

$linklist = new singleLink();
$linklist->insert(1,'hello');
$linklist->insert(2,'my');
$linklist->insert(3,'love');
$linklist->insert(4,'haha4');
$linklist->insert(5,'haha5');
$linklist->insert(6,'haha6');
$linklist->insert(7,'haha7');

$linklist->delete(5);
$linklist->insert(8,'haha8')->insert(9,'haha9')->insert(10,'haha10')->insert(11,'haha11');
var_dump($linklist);
?>

双向链表

冒泡排序

$list = array(39, 38, 22, 45, 23, 67, 31, 15, 41);
$count = count($list);
$num = 0;

$newlist = bubbleSort($list);
print_r($newlist);

function bubbleSort($numbers){
	$cnt = count($numbers);
	for($i=0;$i<$cnt-1;$i++){//循环比较
		for($j=0;$j<$cnt-1-$i;$j++){
			if($numbers[$j]>$numbers[$j+1]){//执行交换
				$temp=$numbers[$j+1];
				$numbers[$j+1]=$numbers[$j];
				$numbers[$j]=$temp;
			}
		}
	}
	return $numbers;
}

快速排序

在这里插入图片描述

$list = array(10,3,5,7,11,45,64,74,23,21,6);

$return = quicksort($list);
var_dump($return);exit;
function quicksort($arr){
    if(count($arr)>1){
        $k=$arr[0];
        $x=array();
        $y=array();
        $size=count($arr);
        for($i=1;$i<$size;$i++){
            if($arr[$i]<=$k){
                $x[]=$arr[$i];
            }else{
                $y[]=$arr[$i];
            }
        }
        $x=quicksort($x);
        $y=quicksort($y);
        return array_merge($x,array($k),$y);
    }else{
        return$arr;
    }
}

简单选择排序

$list = array(10,3,5,7,18,11,45,64,74,23,21,6);
$list = select_sort($list);
print_r($list);
function select_sort($list){
	$count = count($list);
	for ($i=0; $i < $count; $i++) { 
		$k = $i;
		for ($j=$i+1; $j < $count; $j++) { 
			if($list[$k] > $list[$j]){
				$k = $j;
			}
		}
		if($k != $i){
			$tem = $list[$i];
			$list[$i] = $list[$k];
			$list[$k] = $tem;
		}
	}
	return $list;
}

在这里插入图片描述

直接插入排序

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Csoap2/article/details/88216058
今日推荐