双方向連結リストのインサートソートの書き直し

前記事で使ったダブルポインタを利用して書き換えました

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define MAX 30
typedef struct link_tag{
  struct link_tag *next;
  struct link_tag *prev;
  int id;
}linked_list;
void delete_element(linked_list*,int);
void insert_sort(linked_list**);
void insert_list(linked_list*,linked_list*);
void sub_sort(linked_list**,linked_list*);
void regist_element(linked_list**,linked_list*);
int count_list(linked_list*);
linked_list* head_point(linked_list*);
linked_list* create_element(int);
int main()
{
  int i;
  linked_list *head=NULL,*p;
  srand((unsigned)time(NULL));
  for(i=0;i<MAX;i++)
    regist_element(&head,create_element(rand()%MAX));
  for(p=head,i=1;p;p=p->next,i++)
    printf("%d : %d\n",i,p->id);
  printf("sorted : \n");
  insert_sort(&head);
  for(p=head,i=1;p;i++,p=p->next)
    printf("%d : %d\n",i,p->id);
  printf("\n");
  return 0;
}

int count_list(linked_list *list)
{
  int i=0;
  while(list){
    i++;
    list = list->next;
  }
  return i;
}
linked_list* create_element(int id)
{
  linked_list* new;
  if(!(new = (linked_list*)malloc(sizeof(linked_list)))){
    fprintf(stderr,"failed secure memory\n");
    exit(1);
  }
  new->next = NULL;
  new->prev = NULL;
  new->id = id;
  return new;
}
void regist_element(linked_list **former,linked_list* latter)
{
  linked_list *p;
  if(*former == NULL){
    *former = latter;
    return;
  }
  p = *former;
  while(p->next)
    p = p->next;
  p->next = latter;
  latter->prev = p;
}

void insert_sort(linked_list **head)
{
  linked_list *p,*n;
  p = (*head)->next;
  (*head)->next = NULL;
  while(p){
    n = p->next;
    sub_sort(head,p);
    p = n;
  }
}

void sub_sort(linked_list **head,linked_list *el)
{
  linked_list *p = *head;
  if(p->id > el->id){
    el->next = *head;
    (*head)->prev = el;
    *head = el;
    return;
  }
  while(p->next){
    if(p->next->id < el->id)
        p = p->next;
    else
      break;
  }
    insert_list(p,el);
}

void insert_list(linked_list* p,linked_list* t)
{
  if(p->next){
    p->next->prev = t;
  }
  t->next = p->next;
  p->next = t;
  t->prev = p;
}


実行結果

$ ./list
1 : 24
2 : 23
3 : 1
4 : 29
5 : 2
6 : 5
7 : 21
8 : 9
9 : 1
10 : 15
11 : 5
12 : 5
13 : 8
14 : 2
15 : 1
16 : 10
17 : 23
18 : 23
19 : 15
20 : 0
21 : 12
22 : 7
23 : 23
24 : 9
25 : 23
26 : 6
27 : 8
28 : 21
29 : 4
30 : 17
sorted :
1 : 0
2 : 1
3 : 1
4 : 1
5 : 2
6 : 2
7 : 4
8 : 5
9 : 5
10 : 5
11 : 6
12 : 7
13 : 8
14 : 8
15 : 9
16 : 9
17 : 10
18 : 12
19 : 15
20 : 15
21 : 17
22 : 21
23 : 21
24 : 23
25 : 23
26 : 23
27 : 23
28 : 23
29 : 24
30 : 29


メイン関数のfor文をいつもとは変わった書き方をしてみました

単方向連結リストのインサート?ソート

すでにソートされている単方向連結リストに対して、ソートされている状態が崩れないように
新しい要素を挿入するプログラムを書きました

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
#define MAX 100
typedef struct link_tag{
  struct link_tag* next;
  int id;
}link_list;

void LeftInsert(link_list **head,link_list *p,link_list *obj)
{
  if(p == *head){
    obj->next = *head;
    *head = obj;
  }else{
  link_list *pp = *head;
  while(pp->next != p)
    pp = pp->next;
  pp->next = obj;
  obj->next = p;
  }
}

void RightInsert(link_list *p,link_list *obj)
{
    obj->next = p->next;
    p->next = obj;
}
void InsertList(link_list **head,link_list *obj)
{
  if(!(*head)){
    *head = obj;
    return;
  }
  link_list *p = *head;
  if((*head)->id > obj->id){
    LeftInsert(head,p,obj);
    return;
  }else{
    while(p->next)
      if(obj->id > p->next->id)
        p = p->next;
    else
      break;
  }
  RightInsert(p,obj);
}

link_list* CreateLink()
{
  link_list *obj;
  if(!(obj = (link_list*)malloc(sizeof(link_list)))){
    fprintf(stderr,"memory secure error\n");
    exit(1);
  }
  obj->id = rand() % MAX;
  obj->next = NULL;
  return obj;
}

int main()
{
  int i;
  srand((unsigned int)time(NULL));
  link_list *head=NULL,*p;
  for(i=0;i<MAX;i++)
    InsertList(&head,CreateLink());
  p = head;
  while(p){
    printf("%d\n",p->id);
    p = p->next;
  }
}

インサートソートというよりはリストに要素を追加する際にソート済みになるように要素を挿入しているって感じです
すでにあるリストをソートしてる訳ではないのでインサートソートといえるのかちょっと微妙です
双方向リストのインサートソートを書いたときと比べると、コードも簡潔で短くなっていて成長を感じます
headポインタのポインタを関数に持っていくと、先頭を指すポインタが呼び出し先で変更できるので、そこを活かしました。双方向リストのときは、先頭のポインタを呼び出し先で変更するアイデアがなかったので、とりあえずリストの末端に行って、そこから左に調べていくという方法をとっていました(そもそも単方向連結リストだとすぐに左にいくことができず、計算量が大変なことになる)。この方法を採用すれば、headポインタが必ずリストの先頭を指している状態にできるので、右端にポインタを移動させずともソートを開始でき、計算効率が上昇します。

大番長完結!

無茶苦茶モードをクリアして大番長コンプしました!
全キャラキャラクリして最大LVと最大BPも狙って上げてきていたので、
モード自体は楽に攻略できました
全クリしたので感想みたいなものを↓

アリスのゲームだけあってなかなかの中毒性
寝る時間とか土日を削ってPCにかじりついてやってました。
土日は昼飯を食う時間すら惜しかったですね...
主人公の斬真狼牙君、ゲーム中の顔は男前なんですけど、パッケージの顔は写りが悪いのかオネエっぽい...

14年前のゲームにしてはだいぶ良いものだとは思いますが、
えっちなCGが絵師によってばらつきが大きく、あまり統一性がないことにやや不満が残りました
ヒロインだと高羽のCGがやたら気合が入ってるんですが扇奈のCGはいまひとつ足りない感じがします
キャラがたくさんいるので製作の都合上仕方ないんですかね

OPのDash! To Truthいい曲だからきいて

Dash! To Truth

f:id:xxxasdfghjk999:20170710225653p:plain

大番長キャラクリ&CGコンプ

大番長8周目おわりー
ついにCGとキャラクリが全部埋まりました!!!
長かった...
f:id:xxxasdfghjk999:20170710191335p:plainf:id:xxxasdfghjk999:20170710191338p:plainf:id:xxxasdfghjk999:20170710191348p:plain
↑ハードモードだとこんなリザルトが出てくるのね
次は無茶苦茶モードに挑戦して、それで大番長はおわりにしようかな