Gobble up pudding

プログラミングの記事がメインのブログです。

MENU

単方向リスト(Singly Linked List)の実装 (C++)

f:id:fa11enprince:20160518180613j:plain
単方向リストを勉強がてら久々にビールを飲みながらC++で書いてみました。
これをやると、ポインタって何かってよく理解できますね。
しかしビールを飲むと、わけのわからないミスをしでかします…。

ソースコード

#include <iostream>
#include <exception>

namespace My {

    template <typename T>
    class SinglyLinkedList {
    private:
        struct Node {
            T value;
            Node *next;
            Node() : value(0), next(nullptr) {
            }
            ~Node() {
            }
        };
        Node *head_;
        int number_;

        Node *create(T value) {
            Node *node = new Node();
            node->value = value;
            node->next = nullptr;
            return node;
        }
        void destroy(Node *node) {
            delete node;
            node = nullptr;
        }
    public:
        SinglyLinkedList() :
            head_(nullptr)
            ,number_(0) {
        }
        ~SinglyLinkedList() {
            Node *cur = nullptr;
            for (Node *node = head_;
                 node != nullptr;
                 cur = node, node = node->next) {
                destroy(cur);
            }
        }
        void push_front(T value) {
            Node *new_node = create(value);
            if (head_ == nullptr) {
                head_ = new_node;
            }
            else {
                Node *node = head_;
                head_ = new_node;
                head_->next = node;
            }
            number_++;
        }
        void push_back(T value) {
            Node *new_node = create(value);
            if (head_ == nullptr) {
                head_ = new_node;
            }
            else {
                Node *node = head_;
                Node *tail = nullptr;
                for (; node != nullptr; tail = node, node = node->next);
                tail->next = new_node;
            }
            number_++;
        }
        void insert(int pos, T value) {
            Node *new_node = create(value);
            if (pos == 0) {
                push_front(value);
            }
            else if (pos < number_ - 1) {
                Node *prev = nullptr;
                Node *node = head_;
                for (int i = 0; i < pos; ++i) {
                    prev = node;
                    node = node->next;
                }
                prev->next = new_node;
                new_node->next = node;
                number_++;
            }
            else if (pos == number_ - 1) {
                push_back(value);
            }
            else {
                throw std::bad_exception();
            }
        }
        void pop_front() {
            Node *node = head_;
            head_ = node->next;
            destroy(node);
            number_--;
        }
        void pop_back() {
            Node *node = head_;
            Node *prev = nullptr;
            Node *tail = nullptr;
            for (; node != nullptr;
                 prev = tail, tail = node, node = node->next);
            prev->next = nullptr;
            destroy(tail);
            number_--;
        }
        void erase(int pos) {
            if (head_ == nullptr) {
                throw std::bad_exception();
            }
            Node *node = head_;
            if (pos == 0) {
                pop_front();
            }
            else if (pos < number_ - 1) {
                Node *prev = node;
                for (int i = 0; i < pos; ++i) {
                    prev = node;
                    node = node->next;
                }
                prev->next = node->next;
                destroy(node);
                number_--;
            }
            else if (pos == number_ - 1) {
                pop_back();
            }
            else {
                throw std::bad_exception();
            }
        }
        void display() {
            for (Node *node = head_; node != nullptr; node = node->next) {
                std::cout << node->value << ' ';
            }
            std::cout << std::endl;
        }
    };
}

auto main()->int {
    try {
        My::SinglyLinkedList<int> list;
        list.push_back(2);
        list.display();
        list.push_back(3);
        list.display();
        list.push_back(4);
        list.display();
        list.push_front(1);
        list.display();
        list.push_front(0);
        list.display();
        list.insert(1, 3);
        list.display();
        std::cout << "---------" << std::endl;
        list.pop_back();
        list.display();
        list.pop_front();
        list.display();
        list.erase(2);
        list.display();
        list.pop_back();
        list.display();
        std::cout << "---------" << std::endl;
        list.push_back(4);
        list.display();
    }
    catch (std::exception& e) {
        std::cout << e.what() << std::endl;
    }
}

イテレーターがねえ!とか
追加するたびnewしてる…とかいろいろ足りないところありますが、
勉強で書くにはこれで十分でしょう。
双方向リストじゃないと微妙に実用性ないですね。
ちょこっと変えると双方向リストになります。

実行結果

$ ./list.exe
2
2 3
2 3 4
1 2 3 4
0 1 2 3 4
0 3 1 2 3 4
---------
0 3 1 2 3
3 1 2 3
3 1 3
3 1
---------
3 1 4

参考リンクなど

以前にも書いてたな…

MacにEclipse 4.5 Mars に Pleiades導入

Mac版 Eclipseのダウンロード

Eclipse Downloads | The Eclipse Foundation
ここからEclipse IDE for Java EE Developersをダウンロードします

Pleiadesをダウンロード

統合開発環境 Eclipse 日本語化プロジェクト - Pleiades
ここからPleiades All in One 4.5.2のJava 64bit Standard Editionをダウンロードします。

Eclipseのインストール

ダウンロードしたeclipse-jee-mars-2-macosx-cocoa-x86_64.tar.gzを解凍します
その後、Eclipse.appを/Applicationsに移動します
なお、任意のフォルダに移動する場合はCommand + Shift + Gです
さらに、pleiades-e4.5-java_20160312.zipを解凍します
/Applications/Eclipse.appを右クリックしてパッケージの内容を表示を選択します。
次のものをごそっと全部Pleiadesからコピーします
Windowsと違ってフォルダごと移動すると中身が上書きされちゃうので注意です。
なのでFinderでやる場合はフォルダに潜ってファイル全選択をしてコピーがいいと思います。

コピー元 コピー先
pleiades/eclipse/dropins/ /Applications/Eclipse.app/Contents/Eclipse/dropins/
pleiades/eclipse/features/ /Applications/Eclipse.app/Contents/Eclipse/features/
pleiades/eclipse/plugins/ /Applications/Eclipse.app/Contents/Eclipse/plugins/

また、/Applications/Eclipse.app/Contents/Eclipse/eclipse.iniを書き換えます
ファイルの末尾に次を追加してください
javaagentの場所は/Applications/Eclipse.app/Contents/MacOSから見たpleiades.jarのPATHです

-Dfile.encoding=UTF-8
-Xverify:none
-javaagent:../Eclipse/dropins/MergeDoc/eclipse/plugins/jp.sourceforge.mergedoc.pleiades/pleiades.jar

Eclipseを起動します

問題が起こりやすいのでコマンドラインから起動します。
そうすると原因を教えてくれます。
私はjavaagentのPATH指定で一度失敗しました

$ /Applications/Eclipse.app/Contents/MacOS/eclipse

なお、起動時に
「eclipse.appは壊れているために開けません。”ゴミ箱”に入れる必要があります」
というイケてないメッセージが出ましたら
システム環境設定 > セキュリティとプライバシー > ダウンロードしたアプリケーションの実行許可
で全てのアプリケーションを許可に変更してみてください。

はてなブログの目次記法の簡単カスタマイズ


目次記法なるものがあって、これは良い!とおもって使ってみました。
h3, h4などに相当するタグ(はてな記法でいえばアスタリスクですね)が
勝手に目次になってくれるやつですね。

使い方は

[:content]

です。こうすると…

だっさwwwコミュ抜けるわ・・・となるわけです。

CSS改造します

ということでCSSを軽くいじります。
例によってデザインCSSのをいじります。

/* Table Of Content */
.table-of-contents {
    border: 1px solid #e4e4e4;
    padding: 20px 10px 20px 40px;
    list-style-type: none;
    border-radius: 5px;
    font-size: 90%;
    background-color: #eeeeee;
}
.table-of-contents:before {
    content: "目次";
    font-size: 110%;
}
.table-of-contents li,
.table-of-contents ul {
    list-style-type: none;
}
.table-of-contents a:link {
    color: #000000;
    text-decoration: none;
}
.table-of-contents a:hover {
    color: #000000;
    text-decoration: underline;
}

そうすると、多少ましになります。

色が変わっているのはリンク踏んだところです。
ちなみに、マウスオーバーしたときに下線がひかれるようにしています。

LINQを学んでみよう


最近、C#が好きになりかけています。
理由は楽ちんだから。
C#をやろうとすると避けて通れないものにLINQがあります。
別に使わなくてもかけるんだけど、
やっぱりLINQを知らないとほかのソースコードも読めないことがしばしば。
ちょっと勉強しないと使えるようにならないっぽい代物なので、
勉強しましょうってことでおすすめツールの紹介とプチ解説です。

LINQとは

まじめに解説しません。とりあえず、必要最低限でデータベースを使う気がないなら、
LINQ to ObjectとLINQ to XMLさえ学んでおけばOKでしょう。
今回はLINQ to Objectについて学びます。

必要なツール

Visual Studio!!
そりゃそうだって言われるので、今回はそれではなく、
https://www.linqpad.net/
LINQPadなるものがあるのでこれを使いましょう!

LINQ to Objectとは

C#のCollectionの処理ライブラリです。
ListやらDictionaryやらごにょごにょできます。
以上w
使うと便利になりますよってことで積極的に使いましょう。

ざっくり文法

省略できるのもいくつかありますが、まずはとりあえず基本形を。

var query = from [クラス名] 範囲変数名 in コレクション
    where [条件]
    select 範囲変数名

です。

LINQPadで書いてみます。

LINQPadをたちあげたら、上側のLanguageをC# Programに変えてあげて、
プログラムを打ち込みます。

public class 成績
{
    public string 学籍番号 { get; set; }
    public string 教科 { get; set; }
    public int    点数 { get; set; }
}

void Main()
{
    var 全成績 = new List<成績>() {
        new 成績 {学籍番号="S-0001", 教科="国語", 点数=90},
        new 成績 {学籍番号="S-0001", 教科="数学", 点数=80},
        new 成績 {学籍番号="S-0002", 教科="国語", 点数=70},
        new 成績 {学籍番号="S-0002", 教科="数学", 点数=70},
        new 成績 {学籍番号="S-0003", 教科="国語", 点数=20},
        new 成績 {学籍番号="S-0003", 教科="数学", 点数=50},
    };

    var query = from 成績 範囲 in 全成績
        where 範囲.点数 >= 80
        select 範囲;
    foreach (var v in query)
    {
        Console.WriteLine(v);
    }
}

実行ボタンを押すと、割とゴージャスな結果が出ます。
簡単だね!

Listの初期化の書き方言語によって微妙に違うから間違えますね。

間違い例
var 全成績 = new List<成績> {
    new {"S-0001","国語", 90},
    ...
};

とか間違った書き方しててこれでいけないんだっけ???とか思いググってしまいました。
まだまだC#初心者ですね。