前回(【無駄話】感情(「感情階層説」を読んで))の中で「「観念連合(LAAD - Liberal Arts and Academic Discplines)」は、(「心理学には関係がない」と書かれていますが)私の考える「認知の抽象化」をとてもよく説明しています。」と書きましたが、文中で引っかかるところがないわけではありません。それは、
観念と概念
の部分です。
先ず記事では「観念」に関して、
「そもそもの漢字の意味では、「観」が「物事を見て本質を捉える」であり、「念」の意味が「思い」、「気持ち」、「考え」ですので、「観念」の漢字からも意味が想像しやすいです。
したがって、「観念」と言うと、「抽象的な考え」や「対象についての意識・考え」といった意味になります。」
と書かれています。また、その後に人が鉛筆を見ている図があり、観念は、
「この「鉛筆」という対象に対する意識が「観念」です。このとき現実世界にある鉛筆その物とは別に、頭の中に「鉛筆」の「観念」を持っていることになります。」
と書かれています。
次に「概念」に関して、
「漢字の「概」は「全体を均
す」「大体」といった意味ですから、平均的にするという意味が伺えます。これに「考え」を意味する「念」が組み合わさるわけです。
「概念」とは、事物の本質や特徴を捉えて、明確に言語化した考えです。」
とあり、更に
「漠然と「鉛筆」を観念した場合と比較すると、「鉛筆」の「概念」は、より具体的で明確になっていると思います。
抽象と具体という軸で考えると、「観念」は抽象的で、「概念」は具体的であるとも言えます。」
としています。
???
言うまでもなく、「抽象」の辞書的意味は「多くの物や事柄や具体的な概念から、それらの範囲の全部に共通な属性を抜き出し、これを一般的な概念としてとらえること」であり、「抽象的」の反義語は「具体的」です。
実際、その後、次のように述べられており、
↑
「このように、『概念』は『観念』と比較すると、言語化され、明確になっており、具体的なモノに思えるが、現実の対象たる事物に対しては(観念よりも)抽象的であると言えます。」
それはまさにそうであると私も考えます。
となると、
「そもそもの漢字の意味では、「観」が「物事を見て本質を捉える」であり、「念」の意味が「思い」、「気持ち」、「考え」ですので、「観念」の漢字からも意味が想像しやすいです。
したがって、「観念」と言うと、「対象を観察して属性や特性等を抽象する意識・考え」や「対象についての意識・考え」といった意味になります。」
「この「鉛筆」という対象に対する意識が「観念」です。このとき現実世界にある鉛筆その物とは別に、頭の中に別の、様々な「鉛筆」の「観念」を持っていることになります。」
「漢字の「概」は「全体を均
す」「大体」といった意味ですから、平均的にするという意味が伺えます。これに「考え」を意味する「念」が組み合わさるわけです。
「概念」とは、事物の観念(で抽象された属性や特性)の本質や特徴を捉えて、共通するものを明確に言語化した考えです。」
「漠然と「鉛筆」を観念した場合と比較すると、「鉛筆」の「概念」は、より具体的で明確になっていると思います。
抽象と具体という軸で考えると、「観念」は抽象的具体的で、「概念」は具体的抽象的であるとも言えます。」
となるのではないかな?と愚考してしまいます。
(まだ不勉強で、認知心理学でどう考えられているのかはわかりませんが)私自身の経験や内省からコンピューターによる情報処理に譬えると、
<<入力>> 原刺激データ(感覚器からの信号)
↓ 神経ネットワークで延髄、小脳または大脳皮質へ
<<変換>> 脳による記憶可能な形式のデータに変換(認知機能の入力処理)
(ニューロンのシナプス結合-1対多、多対1、多対多等)
視覚(色、輝度等)→3D化や境界判断による図形認識等
聴覚(音程、大きさ、長さ、単音複合等)→音源や音種別認識等
触覚(硬さ、反撥、温度、肌)触り等)→空間形象や素材認識等
↓ etc etc(記憶可能形式のデータが客体化されると「→」となる)
<<客体化>>対象に対する観念として統合、構成し、記憶(データベース)へ
↓ (この客体は「オブジェクト」と同義)
<<抽象化>>上記変換時に使う「評価フィルター」は「入力→客体化」まで
の「経験」により発達し、新しい入力で変化し続ける。→「学習」
その為に細分化された刺激データ形式の抽象化が継続して行われ、
その結果「現実の具体的な客体データ(観念)」とは別の「現実
には存在しないが、情報処理のために脳内に存在する仮想客体デ
ータ(概念)」が発生する。
のようなことが起こっているのではないでしょうか?
知らんけど...
というのは、末尾のような「二分木検索サンプル」が脳の機能の極めて単純にデフォルメしたものの様に感じられたからです。例えば、
(1)キー入力があると、「整数データ」に変換され、
(2)(単純な整数の「大小評価フィルター」を経て、二分木リストという)データ集合に加えら(記憶さ)れ、
(3)検索、並び替え等の「情報処理(概念のような上位知的産物は生成しませんが...)」の対象となります。
人間では、先ずデータ形式が極めて多いだろうし、それが学習により更に発達して行き、感情との結合から様々な評価フィルターが作られ、発展され、新しい知的産物が生み出されてゆくので比較にもなりませんが、
そんな感じ?
程度の意味でお読み下さい。
【BinarySearchTree.cs】(出典をC#5で動くようにし、コメントを追加したもの)
///////////////////////////////////////////////////
// BinarySearchTree
// https://lets-csharp.com/binary-search-tree-cs/
///////////////////////////////////////////////////
using System;
using System.Collections;
using System.Collections.Generic; //List使用の為
using System.Linq; //Select使用の為
//////////////
// Nodeクラス
//////////////
public class Node
{
//メンバーフィールド
public int Key;
public Node Left = null;
public Node Right = null;
//コンストラクター
public Node(int key = 0)
{
Key = key; //引数があればKeyに代入
}
}
//////////////////////////
// BinarySearchTreeクラス
//////////////////////////
public class BinarySearchTree
{
public Node Root {private set; get;} //Rootプロパティ
//挿入メソッド
public void Insert(int value)
{
Node node = new Node(value); //nodeインスタンスの作成
//ルートノードがない場合、それを代入
if (Root == null)
{
Root = node;
return;
}
//ルートがある場合
Node cur = Root; //ポインターをルートに設定
while(true)
{
if(cur.Key > value) //ポインターがvalueより大きければ
{
if(cur.Left == null) //左子が未設定なら
{
cur.Left = node; //左子に代入
return;
}
else
cur = cur.Left; //左子が設定済ならポインターを左子に設定
}
else
{
if(cur.Right == null) //右子が未設定なら
{
cur.Right = node; //右子に代入
return;
}
else
cur = cur.Right; //右子が設定済ならポインターを左子に設定
}
}
}
//検索メソッド
public bool Find(int target)
{
if(Root == null) //ルートノードがない場合、検索失敗
return false;
//ルートがある場合
Node cur = Root; //ポインターをルートに設定
while(true)
{
if(cur.Key < target) //ポインターがtargetより小さければ
{
if(cur.Right == null) //ポインターより大きな値(右子)が無ければ
return false; //検索失敗
else
cur = cur.Right; //ポインターに右子を代入
}
else if(cur.Key > target) //ポインターがtargetより大きければ
{
if(cur.Left == null) //ポインターより小さな値(左子)が無ければ
return false; //検索失敗
else
cur = cur.Left; //ポインターに左子を代入
}
else //ポインターがtargetと同一(cur.Key == target)なら
return true; //検索成功
}
}
//並び替えメソッド
public List<Node> Sort()
{
List<Node> list = new List<Node>(); //Nodeのリストを作成
if(Root != null) //ルートがあれば
{
//DFSメソッドの代わりにActionデリゲートを使って再帰を表現
Action<Node> DFS = null;
DFS = (node) =>
{
if(node.Left != null) //左子があれば
DFS(node.Left); //左子を引数にして再帰処理
list.Add(node); //ノードを追加
if(node.Right != null) //右子があれば
DFS(node.Right); //右子を引数にして再帰処理
};
DFS(Root); //ルートから再帰処理を開始
}
return list;
}
/*
public List<Node> Sort()
{
List<Node> list = new List<Node>(); //Nodeのリストを作成
if(Root != null) //ルートがあれば
{
DFS(list, Root);
}
return list;
//ソート処理(ローカル関数)
void DFS(List list, Node node)
{
if(node.Left != null) //引数nodeの左子があれば
DFS(node.Left); //左子を引数にして再帰処理
list.Add(node); //引数より小さい(大きい)ものがある限り追加する
if(node.Right != null) //引数nodeの右子があれば
DFS(node.Right); //右子を引数にして再帰処理
}
}
*/
//削除メソッド
public bool Remove(int target)
{
//削除対象は存在するか?
Node targetParent = null;
Node removeNode; //削除対象の親ノード
bool isLeft = false; //削除対象は親の左の子か右の子か?
if(Root == null) //ルートノードがない場合、削除失敗
return false;
//ルートがある場合
Node cur = Root; //ポインターをルートに設定
while(true)
{
if(cur.Key == target) //ポインターが削除対象であれば
{
removeNode = cur; //ポインターをremoveNodeに代入してループを抜ける
break;
}
if(cur.Key > target) //ポインターが削除対象より大きければ
{
if(cur.Left == null) //ポインターの左子が無ければ削除失敗
return false;
else //ポインターの左子があれば
{
targetParent = cur; //削除対象の親にポインターを代入
isLeft = true; //左子が対象フラグは真
cur = cur.Left; //ポインターに左子を代入
}
}
if(cur.Key < target) //ポインターが削除対象より小さければ
{
if(cur.Right == null) //ポインターの右子が無ければ削除失敗
return false;
else //ポインターの右子があれば
{
targetParent = cur; //削除対象の親にポインターを代入
isLeft = false; //左子が対象フラグは偽
cur = cur.Right; //ポインターに右子を代入
}
}
}
//(1)削除するノードには子が存在しない。
if(removeNode.Left == null && removeNode.Right == null)
{
if(targetParent != null) //親がいれば
{
if(isLeft)
targetParent.Left = null; //左子を削除
else
targetParent.Right = null; //右子を削除
}
else //親がいなければ
Root = null; //ルートを削除
return true;
}
//(2)削除するノードには左または右のみ子が存在する。
else if (removeNode.Left != null && removeNode.Right == null)
{
if(targetParent != null)
{
if(isLeft)
targetParent.Left = removeNode.Left;
else
targetParent.Right = removeNode.Left;
}
else
Root = removeNode.Left;
return true;
}
else if(removeNode.Left == null && removeNode.Right != null)
{
if(targetParent != null)
{
if(isLeft)
targetParent.Left = removeNode.Right;
else
targetParent.Right = removeNode.Right;
}
else
Root = removeNode.Right;
return true;
}
//(3a)削除するノードの左の子に右の子が存在しない。
else if(removeNode.Left != null && removeNode.Right != null && removeNode.Left.Right == null)
{
if(targetParent != null)
{
if(isLeft)
targetParent.Left = removeNode.Left;
else
targetParent.Right = removeNode.Left;
removeNode.Left.Right = removeNode.Right;
}
else
{
Root = removeNode.Left;
removeNode.Left.Right = removeNode.Right;
}
return true;
}
//(3b)それ以外のケース
else
{
//削除するノードの左の子から最大の値を探索する
cur = removeNode.Left;
Node maxParent = removeNode;
while(true)
{
if(cur.Right != null)
{
maxParent = cur;
cur = cur.Right;
}
else
break;
}
//最大値ノードを削除対象のノードと置き換える
int max = cur.Key;
removeNode.Key = max;
//最大値ノードの親の右子を最大値ノードの左子とする。
maxParent.Right = cur.Left;
return true;
}
}
}
///////////////////////////////////////
// BinarySearchTree サンプルプログラム
///////////////////////////////////////
public class Program
{
static void Main()
{
BinarySearchTree bst = new BinarySearchTree();
while (true)
{
Console.WriteLine("なにをしますか? a:追加 f:検索 r:削除 s:全データの列挙 e:終了");
string cmd = Console.ReadLine();
if (cmd == "a")
{
Console.WriteLine("追加する値(int型)を入力してください");
int? n = ToInt(Console.ReadLine()); //int?はnull代入可能
if(n != null)
{
bst.Insert((int)n);
Console.WriteLine("{0}を追加しました", n);
}
else
Console.WriteLine("不正な入力です");
}
else if (cmd == "r")
{
Console.WriteLine("削除する値を入力してください");
int? n = ToInt(Console.ReadLine());
if (n != null)
{
if (bst.Remove((int)n))
Console.WriteLine("{0}を削除しました", n);
else
Console.WriteLine("{0}は存在しないので削除できません", n);
}
else
Console.WriteLine("不正な入力です");
}
else if (cmd == "f")
{
Console.WriteLine("何を探しますか?");
int? n = ToInt(Console.ReadLine());
if (n != null)
{
if (bst.Find((int)n))
Console.WriteLine("{0}は存在します", n);
else
Console.WriteLine("{0}は存在しません", n);
}
else
Console.WriteLine("不正な入力です");
}
else if (cmd == "s")
{
List<Node> sorted = bst.Sort();
string[] strings = sorted.Select(_ => _.Key.ToString()).ToArray();
Console.WriteLine(string.Join(", ", strings));
}
else if (cmd == "e")
break;
else
Console.WriteLine("不正な入力です");
}
Console.WriteLine("終了");
}
//数字文字列を整数(エラーの場合null)で返す
static int? ToInt(string s)
{
try
{
return int.Parse(s);
}
catch
{
return null;
}
}
}
