『L・DK』上白石萌音&杉野遥亮インタビュー!

C言語で整数データの配列から同じ値のデータを削除する関数 int remove_same_data(int a[],int size)を作成する。
但し、この関数は重複したデータを削除して残った個数(整数)を関数の戻り値として返すものとする。

ちなみにここまで出来ました。
下にある途中の1,2,3ができればこのプログラミングができると思うんですが…
分かる方は知恵を貸してください。よろしくお願いします。

#include<stdio.h>
void swap_array(int a[], int size, int i)
{
int t;
if(i>=0 && i<size-1){
t=a[i];a[i]=a[i+1];a[i+1]=t;
}
}

void mysort(int a[], int size)
{
int i,j;
for(j=size-1;j>0;j--){
for(i=0;i<j;i++){
if(a[i]>a[i+1])
swap_array(a,size,i);
}
}
}

int remove_same_data(int a[], int size)
{
1.sort
2.重複部分を削除する
3.残ったデータの個数を返す
}
int main()
{
int a[]={3,5,2,3,4,2,3,3,6,6,1,2,2,3,5,8,2,9}, size=18;
int i,newsize;

newsize = remove_same_data(a, 18);


for(i=0;i<newsize;i++){
printf(" %d ", a[i]);
}

return(0);
}



1はこれを使えば出来るらしいのですがよく分かりません。
void swap_array(int a[], int size, int i)
{
int t;
if(i>=0 && i<size-1){
t=a[i];a[i]=a[i+1];a[i+1]=t;
}
}

void mysort(int a[], int size)
{
int i,j;
for(j=size-1;j>0;j--){
for(i=0;i<j;i++){
if(a[i]>a[i+1])
swap_array(a,size,i);
}
}
}



2はこれを使えばできるらしいのですがなかなかできません。
#include<stdio.h>
int main()
{
int a[8]={1,3,3,4,4,5,6,6},size=8;

//ソート済みデータの重複の削除
int i,j,p;
p=a[0];//前のデータの記憶
j=0;//削除するデータ数を数える
for(i=1;i<size;i++){
if(p==a[i]){
j=j+1;
}
else{
a[i-j]=a[i];//削除するデータ数分前へ
p=a[i];
}
}


//配列の表示
for(i=0;i<size-j;i++){
printf("%3d ", a[i]);//ここで1,3,4,5,6と表示される
}
return(0);
}

このQ&Aに関連する最新のQ&A

A 回答 (4件)

★質問者さんへ。


>ちなみにここまで出来ました。
>下にある途中の1,2,3ができればこのプログラミングができると思うんですが…
>分かる方は知恵を貸してください。よろしくお願いします。
 ↑
 swap_array()…正しい
 mysort()…正しい
 remove_same_data()…1.2.3 の通りに処理を記述すればよいだけです。
 処理手順は
>2はこれを使えばできるらしいのですがなかなかできません。
 ↑
 これで良いと思います。
・よってもう正しく重複データを削除できると思います。
 何をアドバイスすればよいのでしょうか?
 私も『補足要求』しますね。
・ちなみに remove_same_data() 関数は 1.2.3 の手順どおりに
 int remove_same_data( int a[], int size )
 {
  int i, j, p;
  
  // ソート
  mysort( a, size );
  
  //ソート済みデータの重複の削除
  p = a[0]; //前のデータの記憶
  j = 0; //削除するデータ数を数える
  for ( i = 1 ; i < size ; i++ ){
   if( p == a[i] ){
    j = j + 1;
   }
   else{
    a[ i - j ] = a[ i ];//削除するデータ数分前へ
    p = a[ i ];
   }
  }
  return size - j;
 }
 ↑
 で良いでしょう。
・それでは。また。
    • good
    • 0

下の回答者です。


すみません。自分の勘違いでしたね。
このプログラムで正解です。 申し訳ありませんでした。
    • good
    • 0

***** はじめまして *****



>2はこれを使えばできるらしいのですがなかなかできません。

少々細かいところでミスをされているようです。
おそらく実験?的に用意した配列{1,3,3,4,4,5,6,6}を元に実行した結果、1,3,4,5,4と標示されるのではないでしょうか?

重要なのは最後に重複して発見された数字の処理です。このプログラムでは次の値が重複でないときに初めて的確な位置に挿入されるため、最後に重複した文字は正しい位置に挿入されません。
よって示されたプログラムを少々変更する必要があります。

***** 提示していただいたプログラム *****
for(i=1;i<size;i++){
if(p==a[i]){
j=j+1;
}
else{
a[i-j]=a[i];//削除するデータ数分前へ
p=a[i];
}
}



***** 修正したプログラム ***** (見やすくするため、全角のスペースを入力します)
for(i=1; i<size; i++){
  if(p==a[i]){
     j=j+1;
     if(i == (size - 1))
       a[i-j]=a[i];
  }
  else{
  a[i-j]=a[i];//削除するデータ数分前へ
  p=a[i];
  }
}
    • good
    • 0

もう出来ておるようにお見受けしますが。

    • good
    • 0

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

QC言語・要素除去

配列を用意して、それぞれ実体として、さまざまな値を入れたとしたとき、

その配列の、ある要素と、別の要素に重複した値があったとします。

ここで、
重複した値を取り除いて、取り除いた分、そのあと、要素番号を詰める。

という作業をしたいのですが、どのような手順がありますでしょうか。


考え方を知りたいので、できれば、ソースより言葉で教えていただけるようお願いします。

Aベストアンサー

私はソートを利用した方法を提案します。
これなら配列の数が非常に多くても効率よく処理できると思います。

1.配列は値とポインタと削除フラグの3つを対にした構造体の配列にする
2.同じ配列をもう一つ作成して内容をコピーする
3.コピーした配列のポインタは元の配列へアクセスできるようにセットする
4.コピーした配列をソートする(ペアのポインタも一緒にしてソートする)
5.ソートした配列のポインタから元の配列へアクセスして相互にアクセスできるようにポインタをセットする

つまり、同じ配列を用意して片方はソートで並び替えて、互いに対のポインタを通して配列の値を読み取れるようにします。
この下準備ができれば、次の手順で同じ番号を詰める事ができます。

1.削除フラグには配列の番号を入れておく
2.配列を最初から読み取って、ソートした方の配列の前後の値を読み取る
3.もしソートした方の配列の前後の値がどちらも違えば、その配列の値は一つだけなので、そのまま次へ
4.ソートした配列で前の値が違って、後の値が同じなら、それは最初に出てきた値なので、そのまま次へ
5.上記の2つの条件で、それ以外だったなら二回目以降の重複する値なので、削除フラグを立てる(99999など大きい値にする)
6.配列を最後まで読み取ったら、削除フラグでソートすると重複した値だけ後ろの方に移動します。
順番に詰めるよりもソートを利用する方がかなり高速になります。

ここで注意するのはソートのアルゴリズムでクイックソートだと同じ値の順番が元の順番と違う場合があるので(安定ソートでない)比較する値を操作して安定ソートにさせるか、他の安定なソートのアルゴリズムを使う必要があります。

私はソートを利用した方法を提案します。
これなら配列の数が非常に多くても効率よく処理できると思います。

1.配列は値とポインタと削除フラグの3つを対にした構造体の配列にする
2.同じ配列をもう一つ作成して内容をコピーする
3.コピーした配列のポインタは元の配列へアクセスできるようにセットする
4.コピーした配列をソートする(ペアのポインタも一緒にしてソートする)
5.ソートした配列のポインタから元の配列へアクセスして相互にアクセスできるようにポインタをセットする

つまり、同じ配列を用意し...続きを読む

Qint型からchar型への変換

タイトル通り、int型からchar型への変換の仕方がわかりません!><
どうしたらいいのでしょうか?

Aベストアンサー

#include <stdio.h>


char buf[5];
int no;

no = 10;
sprintf(buf, "%d", no);

QC言語 配列の長さの上限

C言語で配列Array[N]の長さNの上限っていくらなんでしょうか?
もし可能なのであれば上限を2147483647にしたいのですが、方法を教えてください。

Aベストアンサー

そもそもWindowsの32bit版はアプリが仮想メモリ空間を2GBしか使えません。2GBを超えるには64bit版が必要です。
たとえ64bit版OSだとしても添え字が2147483647って、単純なintの配列だとしても4x2147483647=8GB必要ですね。実メモリ16GBとかのPCを用意しますか?
そもそも配列で2147483647個必要なアルゴリズムに問題ありだと思います。

Q指定した文字を削除したい

こんにちは。質問をさせてください。

---------------------------------------------------------------
address = "ここ$http://www.aaaaa.co.jp$moji=dddd$";
---------------------------------------------------------------
変数addressに格納された文字列で、
"http://"の1文字前に"$"があった場合は、
"$"を削除したいのですが、どのようにすれば
いいでしょうか?
※http://の前の"$"以外はそのまま残します。

Aベストアンサー

#include <iostream>
#include <string>

int main() {
std::string address = "ここ$http://www.aaaaa.co.jp$moji=dddd$";
std::string::size_type pos = address.find("$http://");
if ( pos != std::string::npos ) {
address.erase(pos,1);
}
std::cout << address << std::endl;
return 0;
}

Q複数桁10進数の*桁目だけを抽出したい

タイトルがすべてと言えてしまうのですが、
例えば、int宣言された"4287"(この値は変動します)という数値があったとして、1桁目の"7"だけを別の変数へ引き抜きたいのですが、その場合にはANDによるマスク処理による演算で処理可能なのでしょうか?
また、他に良い方法などありましたら教えていただけますでしょうか?

Aベストアンサー

★10進数ですので AND は使えませんね。
・簡単なサンプルを載せますので読み取って下さい。

サンプル1:
int value = 4287;
int a[ 4 ];

a[0] = (value % 10); value /= 10; // 1桁目を取り出す
a[1] = (value % 10); value /= 10; // 2桁目を取り出す
a[2] = (value % 10); value /= 10; // 3桁目を取り出す
a[3] = (value % 10); value /= 10; // 4桁目を取り出す

サンプル2:
int value = 4287;
int a;

a = (value % 10);
value -= a;

value → 4280
a → 7
になります。

Qクイックソートしながら重複要素削除アルゴリズム

アルゴリズムが苦手な上、アルゴリズム解説自体C言語ベースで書かれ
ている物が多く処理のイメージが沸かずクイックソートもコピペや既存
の関数で処理していて、満足に理解出来ていないのですが。
以下の問題を、お解かりになるかた教えて頂けませんでしょうか?

■問題
2万件位の数値データの中から重複要素を削除しながら昇順または降順で、
ソートするアルゴリズム(※1)

■条件
BASIC的(※2)な記述やプログラム中のコメントなどの形式でも構いま
せん出来るだけ簡単に示して頂けると助かります。

補足
(※1)ソートする際、重複要素を消すともっと処理が早くなるのではと
思ったので。
目的は、処理の速さを求める事と、次回から応用が聞くよ
うにソート自体を理解したいのでクイックソートで無くても構いません。

(※2)実際に動かなくても構いません、イメージが掴みやすい方が良いと
   いう意味でとって下さい。

Aベストアンサー

>pythonで実行してみたのですが、うまく行きませんでした。
>2行目のIf文でエラーが出るようです。
投稿するとインテンドがきえてしまいました。以下のタブをタブに替えてください。
def qsort(list):
タブif len(list) != 0:
タブタブlt_list = [x for x in list if x < list[0]]
タブタブgt_list = [x for x in list if x > list[0]]
タブタブreturn qsort(lt_list) + [list[0]] + qsort(gt_list)
タブelse:
タブタブreturn []

>他の言語で置き換えようと調べてみたのですが、
>以下の解釈が解からないためよろしければ、教えて頂けるとありがたいのですが。
>3行目、4行目→x for x in list if x
これはpythonのリスト内包表記といって配列の中からある条件の配列を取り出しています。
gt_list = [x for x in list if x > list[0]]
はVBでいうと
for each x in list
if x > list(0) then
gt_listにx追加
end if
next
と同じです。
>ちなみに、以下は
>qsort(lt_list) + [list[0]] + qsort(gt_list)
>ソートと重複削除済みのリストが戻されると解釈して良いのでしょうか?
そうです。[list[0]]にはひとつしか値が入らないし、
lt_list,gt_listにもlist[0]と同じ値は入ってませんよね。

>pythonで実行してみたのですが、うまく行きませんでした。
>2行目のIf文でエラーが出るようです。
投稿するとインテンドがきえてしまいました。以下のタブをタブに替えてください。
def qsort(list):
タブif len(list) != 0:
タブタブlt_list = [x for x in list if x < list[0]]
タブタブgt_list = [x for x in list if x > list[0]]
タブタブreturn qsort(lt_list) + [list[0]] + qsort(gt_list)
タブelse:
タブタブreturn []

>他の言語で置き換えようと調べてみたのですが、
>以下の解釈が解...続きを読む

QC言語で文字列をかえす正しい書き方が知りたいです?

C言語で次の警告が表示されます。
文字列を返したいのですが、正しい書き方はどのようにすれば良いのでしょうか?


jci.h(20) : warning C4172; ローカル変数またはテンポラリのアドレスを返します。


char *test(char *a, int b)
{
char str[BUFSIZ];
return str; <------

}

Aベストアンサー

再入可能にするかどうかで、回答は変わります。

A.2度呼び出した場合に前のデータを破壊してもよいケース(再入不可能)

char *test(...)
{
static char str[BUFSIZ]; // static指定でメモリは静的に確保されます。

...

return str;
}

B.2度呼び出した場合に前のデータを破壊しないケース(再入可能)
B-1.mallocを使ってもいいケース
char *test(...)
{
char *str;
str = malloc(BUFSIZ);
if(str == NULL) return NULL; // エラー

...

return str;
}
この場合は、呼び出し元でちゃんとfreeしましょう。

B-2.呼び出し元でメモリを確保するケース
(注意:同じアドレスを指定して複数回呼び出すと、メモリ内容は当然破壊されます)
char *test(char *str, ...)
{

...

return str;
}
これは#1の方の回答と同じです。

B-3.B-1/B-2の複合
(注意:NULL以外の同じアドレスを指定して複数回呼び出すと、メモリ内容は当然破壊されます)
char *test(char *str, ...)
{
if(str == NULL)
{
str = malloc(BUFSIZ);
if(str == NULL) return NULL; //エラー
}

...

return str;
}

こんなところですかね。

再入可能にするかどうかで、回答は変わります。

A.2度呼び出した場合に前のデータを破壊してもよいケース(再入不可能)

char *test(...)
{
static char str[BUFSIZ]; // static指定でメモリは静的に確保されます。

...

return str;
}

B.2度呼び出した場合に前のデータを破壊しないケース(再入可能)
B-1.mallocを使ってもいいケース
char *test(...)
{
char *str;
str = malloc(BUFSIZ);
if(str == NULL) return NULL; // エラー

...

return str;
}
この場合は、呼び...続きを読む

Q変数が""(空文字)かどうか判別する方法

度々お世話になります。

C++で""(空文字)かどうかを判別する方法はありますか?
私は単純にstrcmpで文字列比較をすればいいと思っていたのですが、
TLSを使用しているためか、なぜかうまくいきません。

// 変数宣言&取得(Setは省略)
__declspec( thread ) char tls_Name [12] = "";

const char * TlsGetName( void )
{
return tls_Name;
}

// 取得&判別(スレッド内処理)
if (strcmp(TlsGetName(),"") == 0)
処理A
else
処理B

このとき、初回実行時は処理Aに行ってくれるのですが
2回目の実行以降はtls_Nameが""であるにもかかわらず
処理Bに行ってしまいます。

どこかおかしな所やもっといい方法がありましたら教えてください。

Aベストアンサー

strlen()で長さが0であれば、空の文字列
もしくは
if( tls_Name[0]=='\0' ) {
文字列が空の時の処理
}

Qファイルの中身検索と表示

Cでの作成についてなんですが、
fopenでテキストファイルを開き、テキストの中身の
特定文字が含まれている行を新に作ったファイルの中に
書き込みたいんですが、テキストの中身の検索と
抽出方法がいろいろ試してみましたがわかりません。
よろしくお願いします。

Aベストアンサー

★文字列の検索関数を使えば良い。
・テキストの中身の検索は、行単位で文字列を取得(fgets)してから、この文字列内に
 検索文字列の有無をチェックします。この有無は文字列から文字列を検索する関数
 『strstr』関数を使うのが便利です。また、文字列から1文字の検索を行う場合は
 『strchr』関数を使います。質問では、特定の文字が含まれている行となっていますが
・検索するのは1文字、文字群、文字列のどれですか?
 これによっていろいろと代わりますよ。処理が…。
・とりあえず文字列から特定の文字列を含まれた行を抽出するサンプルを下に載せます。

サンプル:
char buff[ 256 ];
char *find = "検索文字列";
FILE *fp; ←読み込み用
FILE *fo; ←抽出用

省略(fopen×2つ)

while ( fgets(buff,sizeof(buff),fp) != NULL ){
 if ( strstr(buff,find) != NULL ){
  fputs( buff, fo );
 }
}

省略(fclose×2つ)

解説:
・上記のサンプルでは、行単位でテキストの中身を取得して、この文字列から検索文字列(find)が
 含まれるか『strstr()』関数でチェックしています。見つかると『NULL』以外を返します。
・そして、見つかったらば行単位で『fputs』関数で出力しています。
 これで見つかった行だけが、新たに作ったファイルに書き込まれていきます。→抽出です。
・また『strstr()』関数の部分を
 『if ( strchr(buff,'a') != NULL ){ … }』とすると『a』の文字が含まれる行のみを抽出します。
 『if ( strspn(buff,"+-*/") != 0 ){ … }』とすると『+-*/』の文字群が含まれる行のみを抽出します。
 検索する文字とは、1文字、文字群、文字列のどれですか?
・以上。おわり。→上記のを参考にして下さい。

参考URL:http://www9.plala.or.jp/sgwr-t/lib/strspn.html,http://www9.plala.or.jp/sgwr-t/c/sec17.html

★文字列の検索関数を使えば良い。
・テキストの中身の検索は、行単位で文字列を取得(fgets)してから、この文字列内に
 検索文字列の有無をチェックします。この有無は文字列から文字列を検索する関数
 『strstr』関数を使うのが便利です。また、文字列から1文字の検索を行う場合は
 『strchr』関数を使います。質問では、特定の文字が含まれている行となっていますが
・検索するのは1文字、文字群、文字列のどれですか?
 これによっていろいろと代わりますよ。処理が…。
・とりあえず文字列から特定...続きを読む

Q#defineの定数を文字列として読み込む

#define A "xxx"
#define B "yyy"
と定義しておいて

scanf("%s", str)
で読み込んだ文字列strが
"xxx"だった場合、"yyy"だった場合のように分岐したいのですが
このとき

if(str == "xxx")
のように中身を指定するのではなく

if(str == AA)
のように定数で分岐させることってできますか?

上記のままではできませんが、何か特別な関数とかでできるのでしょうか?

Aベストアンサー

こんにちは。

やりたいことの解釈ですが、(※勘違いの場合はすみません。)

1)マクロの名前(定義名)が文字列として格納された文字列 str があるとする。
 例)
   #define A "xxx"  //マクロ名=A
   char str[] = "A";   //"A"はマクロ名

2)上記の文字列 str を関数 func に渡す際に、マクロ名ではなくそのマクロで
  定義された文字列を渡したい。
 例)
   func( str );    //←この場合
    ↓
   func( "xxx" );  //←として展開される

ということで宜しいでしょうか?

だとした場合、少し回りくどいやり方かもしれませんが、以下のような文字列
変換用のマクロを定義してみては如何でしょうか?
※基本的には、他の回答者の方と同じように strcmp関数 を使用します。

■マクロ例
==============================
//文字列を定義したマクロ …※1
#define A "xxx"
#define B "yyy"

//引数を文字列として取得するマクロ
#define GETSTR(x) #x

//引数をマクロ名としてそのマクロで定義された文字列を取得するマクロ …※2
//注)<string.h>がインクルードされていることを前提とする
#define STR2MAC(str) \
!strcmp(str,GETSTR(A))? A : \
!strcmp(str,GETSTR(B))? B : str
==============================

上記マクロを使用して、関数 func にマクロ名が格納された文字列 str を
渡す場合は、
   func( STR2MAC( str ) );
のような記述になります。

前提として、※2のマクロ内でstrcmp関数を用いて文字列の照合を行って
いますので、<string.h>のインクルードが必要になります。

また、※1の文字列を定義するマクロの種類(パターン)を増やす場合、
※2のマクロの判定文もそれに合わせて増やす必要があります。

上記のマクロを使用したサンプルソースを下記に掲載致します。
注)エラー処理は行っていません。

■サンプルソース
==============================
#include <stdio.h>
#include <string.h>

//文字列を定義したマクロ
#define A "xxx"
#define B "yyy"

//引数を文字列として取得するマクロ
#define GETSTR(x) #x

//引数をマクロ名としてそのマクロで定義された文字列を取得するマクロ
//注)<string.h>がインクルードされていることを前提とする
#define STR2MAC(str) \
!strcmp(str,GETSTR(A))? A : \
!strcmp(str,GETSTR(B))? B : str

//プロトタイプ
void funcHoge( const char *str );

int main(void)
{
char sArg[128];

printf( "A or B ?>" );
scanf( "%s", sArg );

printf( "string1: %s\n", sArg );
funcHoge( STR2MAC(sArg) );

return 0;
}

void funcHoge( const char *str )
{
printf( "string2: %s\n", str );
}
==============================

■上記サンプルの実行結果
≫実行その1≪
A or B ?>A
string1: A
string2: xxx

≫実行その2≪
A or B ?>B
string1: B
string2: yyy

≫実行その3≪
A or B ?>hoge
string1: hoge
string2: hoge

以上です。

こんにちは。

やりたいことの解釈ですが、(※勘違いの場合はすみません。)

1)マクロの名前(定義名)が文字列として格納された文字列 str があるとする。
 例)
   #define A "xxx"  //マクロ名=A
   char str[] = "A";   //"A"はマクロ名

2)上記の文字列 str を関数 func に渡す際に、マクロ名ではなくそのマクロで
  定義された文字列を渡したい。
 例)
   func( str );    //←この場合
    ↓
   func( "xxx" );  //←として展開される

ということで宜しいでしょう...続きを読む


このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング