キュー/スタック/チェーン
キュー
質問:パトリシアはまた、小さなハムの復号化ルールを告げながら、パトリシアが小さいハムと新しいテーブルで、少しパトリシア問い合わせQQにハム、パトリシアは、暗号化されたデジタルの小さなハムの束を与えました。そのような規則は以下の通りである。まず、この番号の末尾に2番目の文字列の数に続く最初の削除の数が、第3の数と第四の数は、文字列の終わりに、この番号を削除し、そしてします数5は、最後に残った数まで、最後の番号も削除されて...削除しました。ただ、順序を削除し、一緒にこれらの番号を削除することは、小さなカザフQQの友人です。パトリシアはハム、暗号化された文字列の数が少ない「631758924.」であります
アイデア:
- 最初のステップは、あなたはまだ、アレイ内の番号を削除する方法を考えることができ、復号化された最初の数字を削除することです。最も簡単な方法は、すべての王Qianmian移動1、フロントカバーの数の後ろにある数えることです。私たちのようなチケットを買うために並んで、私はすべての人々が、すべては、前後に向けた一歩を踏み出す前に、欠員を埋める必要がある、左の人の前に買ったが、このアプローチは非常に時間がかかるです。ここで私は2つの整数の変数頭と尾を紹介します。キュー(すなわち、最初の)の待ち行列の先頭に記録するためのヘッドは、テールキュー(即ち、最後)の次の位置の尾を記録するために使用されます。あなたは求めることができる:尾は直接尾、チームの尾の次の位置を記録しませんなぜこれが唯一の要素、キューの先頭と末尾のオーバーラップは、いくつかのトラブルの原因となりますキューがあるので、それを記録する必要が?。最初のチームとテール偶然の規定は、キューが空になったとき、私たちはここにあります。
- 尾= 10;ヘッドとテールキューの間で、この時点で数が現在「アクティブ」番号の後にすべてのキュー・ヘッド= 1に入れて数9、数9は、あります。あなたは単語の数を削除したい場合は、それはOK ++向かいますので、あなたはまだ現在のキュー「有効」の数の頭と尾数の間に残ることができます。そのスペースの無駄をしながら、それは非常に費用対効果のある、多くの時間を節約できます。新しい番号は、またOKに尾を++再後のQ [尾]である尾に数を増やす必要が非常に簡単です追加します。
- イラスト:
コード:
#include <stdio.h>
int main()
{
int q[102]={0,6,3,1,7,5,8,9,2,4},head,tail;
int i;
//初始化队列
head=1;
tail=10; //队列中已经有9个元素了,tail指向队尾的后一个位置
while(head<tail) //当队列不为空的时候执行循环
{
//打印队首并将队首出队
printf("%d ",q[head]);
head++;
//先将新队首的数添加到队尾
q[tail]=q[head];
tail++;
//再将队首出队
head++;
}
getchar();getchar();
return 0;
}
要約:
- キューのみと呼ばれるキューヘッダ(ヘッド)削除操作、「デキュー」を挿入する操作が呼び出されたキュー(テール)の尾部で行われる「エンキュー」特殊線形構造が可能です。いかなるキュー要素(すなわち、ヘッド==尾部)がない場合、空のキューと呼ばれます。
- キューは、ベルマン - フォード最短経路アルゴリズムの将来のコアデータ構造学習幅優先探索およびキュー最適化されます。だから今キュー(2つの変数の配列)の三つの基本的な要素は、パッケージ構造タイプに、次のように。
struct queue
{
int data[100];//队列的主体,用来存储内容
int head;//队首
int tail;//队尾
};
以下、上記のようにコードを変更します
#include <stdio.h>
struct queue
{
int data[100];//队列的主体,用来存储内容
int head;//队首
int tail;//队尾
};
int main()
{
struct queue q;
int i;
//初始化队列
q.head=1;
q.tail=1;
for(i=1;i<=9;i++)
{
//依次向队列插入9个数
scanf("%d",&q.data[q.tail]);
q.tail++;
}
while(q.head<q.tail) //当队列不为空的时候执行循环
{
//打印队首并将队首出队
printf("%d ",q.data[q.head]);
q.head++;
//先将新队首的数添加到队尾
q.data[q.tail]=q.data[q.head];
q.tail++;
//再将队首出队
q.head++;
}
getchar();getchar();
return 0;
}
スタック
スタックと呼ばれるLIFOデータ構造もあります。一端のみでの挿入や削除のように定義スタック。
質問1:回文を決定
質問:例を見てみましょう。「Xyzyx」回文が文字列で、文字列が回文正しい読み倒語と呼ばれるような、同じ文字シーケンスです「席の社長、」「「AHAHAなるほど」、「秘書を覚えている」とは、」回文ですが、 「AHAH」ではない回文。このスタックデータ構造とは、文字列が回文かどうかを判断するのは非常に簡単になります。
アイデア:
- まず、我々は、この行の文字列を読み込み、文字列の長さを見つける必要があります。文字列が回文である場合、それは、中央と左右対称でなければならない、我々はすなわち:ミッド= LEN / 2-1、中間点を要求し、我々は最初の半ば、すべての文字をスタックする前に。ここためスタックは、文字を格納するために使用されるので、アレイのこのタイプは、実装するために使用されるスタック、すなわち文字列チャーS [101];、スタックの初期化が簡単であり、0 =トップ、それ。(スタックを仮定すると、文字変数xに一時的な文字を必要とする)、実際には、Sと略記することがある[++トップ] = xと; S [トップ] = xと;上部++ある動作を描きます。
- 次に、キー決意ステップパリンドロームを入力してください。現在のスタックの文字ができ、この文字列の説明と一致する場合は、ミッド後の文字と一致する1つの回文文字列である、または文字列が回文文字列ではありませんかどうかを確認するために、スタックを消します。
コード:
#include <stdio.h>
#include <string.h>
int main()
{
char a[101],s[101];
int i,len,mid,next,top;
gets(a); //读入一行字符串
len=strlen(a); //求字符串的长度
mid=len/2-1; //求字符串的中点
top=0;//栈的初始化
//将mid前的字符依次入栈
for(i=0;i<=mid;i++)
s[++top]=a[i];
//判断字符串的长度是奇数还是偶数,并找出需要进行字符匹配的起始下标
if(len%2==0)
next=mid+1;
else
next=mid+2;
//开始匹配
for(i=next;i<=len-1;i++)
{
if(a[i]!=s[top])
break;
top--;
}
//如果top的值为0,则说明栈内所有的字符都被一一匹配了
if(top==0)
printf("YES");
else
printf("NO");
getchar();getchar();
return 0;
}
それはまた、検証括弧のマッチングのために使用することができるスタック。入力文字列が一つだけの行を含んでいるような"()[] {}"を決定してください
フォーム"([{}()])"または"{()[] {}}"かどうか、正しい一致し。
質問2:ポーカーゲーム - 猫釣り
質問:ゲームのルールはこれです:カードの平均デッキがそれぞれ1つを保持し、2分け。まあ最初の最初のテーブルの上に小さなトランプの手のうち、この2つの代替のように、その後、パトリシアはまた、トランプの手の中に最初のかかった、と小さなハムの上だけでポーカーをプレイカード。ときにカードを誰かがテーブルの上に同じカードとカードフェイスカードをプレイした場合、2枚のカードは同じカードと削除されたすべてのクリップの真ん中こと、そしてターンで最後に手にカードを置くことができます。すべてのカードの手の中にそれらのいずれかが出てプレイすると、ゲームは、試合の勝利を終了します。
ゲーム開始時に、カードの手の中に6つの小さなハム、241256のオーダーがある場合、パトリシアはまた、カードの6手、313564の順番を持ち、そして最終的には勝つだろう誰が?今、あなたは思い付くことができますソリティアをしてみてください。そして、あなたは自動的に勝つ者を決定するためのプログラムを書きます。ここでは、慣例、小さなハムとパトリシアカードポーカーの手の顔のみ1-9を行います。
アイデア:
- まず、次のようにのは、キューを実装するために使用される構造を作成してみましょう
struct queue
{
int data[1000];
int head;
int tail;
}
その後、次のようにスタックを実装するために使用する構造を作成します。
struct stack
{
int data[10];
int top;
};
トップスタックを格納するために使用されるデータ配列要素をスタックに格納されているため、サイズは10に設定されています。唯一の9種類の顔カードなので、テーブルには、最大9枚のカードを持っていることがあり、その配列のサイズが10に設定されて十分ですので。リマインダー:なぜゼロベースで9 C言語の配列インデックスとして設定?。
次に我々は、2つの変数のキューのQ1とQ2を定義する必要があります。Q1は小さなハム彼らの手、小さなシミュレートするために使用Q2シミュレートするために使用
カザフに彼らの手を。変数sを定義し、テーブルの上にカードのスタックをシミュレートするために使用されます。
struct queue
struct stack
q1,q2;
s;
その後、キューを見て、スタックを初期化します。
//初始化队列q1和q2为空,此时两人手中都还没有牌
q1.head=1; q1.tail=1;
q2.head=1; q2.tail=1;
//初始化栈s为空,最开始的时候桌上也没有牌
s.top=0;
次は6番を読んたびは、Q1とQ2に挿入された、二回、カードの手の中に、最初は小さなハムとパトリシアを読んで読んでする必要があります。
//先读入6张牌,放到小哼手上
for(i=1;i<=6;i++)
{
scanf("%d",&q1.data[q1.tail]); //读入一个数到队尾
q1.tail++;//队尾往后挪一位
}
//再读入6张牌,放到小哈手上
for(i=1;i<=6;i++)
{
scanf("%d",&q2.data[q2.tail]); //读入一个数到队尾
q2.tail++;//队尾往后挪一位
}
今の製剤は、基本的に第1の小ハムを再生、ゲームが開始、行われています。T = q1.data [q1.head]; //小さいハムハムは、最初のキューQ1の先頭である第一のカードを再生する小さなカードを示したが、このカードは、一時変数tに格納されます。その後、我々はテーブルの上に、現在の小さなハムプレイカードが手を獲得するかどうかを決定する必要があります。?それは、テーブルカードなしトンの判断は、次のように同じことが、それを達成するためにどのように我々は、比較のためのtテーブルと各カードを列挙する必要があります。
flag=0;
for(i=1;i<=top;i++)
{
if(t==s[i]) { flag=1; break; }
}
如果 flag 的值为 0 就表明小哼没能赢得桌上的牌,将打出的牌留在桌上。
if(flag==0)
{
//小哼此轮没有赢牌
q1.head++; //小哼已经打出一张牌,所以要把打出的牌出队
s.top++;
s.data[s.top]=t; //再把打出的牌放到桌上,即入栈
}
1のフラグ値が小さいハムがテーブルの上にカードを勝つことができることを示すことになるならば、
我々はカードが小さなハムの手に入れて勝利する必要があります。
f(flag==1)
{
//小哼此轮可以赢牌
q1.head++;//小哼已经打出一张牌,所以要把打出的牌出队
q1.data[q1.tail]=t; //因为此轮可以赢牌,所以紧接着把刚才打出的牌又放到手中牌的末尾
q1.tail++;
while(s.data[s.top]!=t) //把桌上可以赢得的牌(从当前桌面最顶部一张牌开始取,直至取到与打出的牌相同为止)依次放到手中牌的末尾
{
q1.data[q1.tail]=s.data[s.top]; //依次放入队尾
q1.tail++;
s.top--; //栈中少了一张牌,所以栈顶要减1
}
}
シミュレーション上の小さなハムカードのすべてのステージが終わって、小さなカードや小さなハムHachuカードは同じです。その後、我々はゲーム終了方法を決定する必要があります。それは限り、二つのゲームのカードがなくなった人を超えているようです。シミュレーションでは、次の2枚のカードは、whileループを決定するためのコードを追加外必要があります。
キューQ1、Q2が空ではありません(q1.head <q1.tail && q2.head <q2.tail)//最後のステップの実行サイクル中に、最終的にゲームに勝った方の出力、およびの手の中にゲームの勝者の後カードやテーブルカード。小さなハムの勝利は、それほどの手の中に確かにカードパトリシア(Q2キューが空である)場合、すなわちq2.head == q2.tailは、特定の出力は次のようです。
if(q2.head==q2.tail)
{
printf("小哼win\n");
printf("小哼当前手中的牌是");
for(i=q1.head;i<=q1.tail-1;i++)
printf(" %d",q1.data[i]);
if(s.top>0) //如果桌上有牌则依次输出桌上的牌
{
printf("\n桌上的牌是");
for(i=1;i<=s.top;i++)
printf(" %d",s.data[i]);
}
else
printf("\n桌上已经没有牌了");
}
}
それどころか、パトリシアは、コードを達成するために、勝つためにはほぼ同じですが、それらを繰り返すことはしません。これは、それが終了しているすべてのコードを達成するためには、我々はすべての誰もがカードをプレイした後、上記の説明を、実現し、これを最適化することができ、勝利の手かどうかを判断します。私たちはテーブルの上にすべてのカードの順番を決定するためのループを使用したことを達成するために、テーブル上のすべてのカードを列挙する前にカードのプレイに等しいです。実際には、この問題を解決するためのより良い方法があり、テーブルの上に何枚のカードを記録するために、配列を使用することです。のみ1-9サイン顔なので、これだけすでにそれを顔に署名テーブルの上に現在あるものを記録するために、サイズ10の配列を開きます。
int book[10];
ここで、私はもう一度、登録、およびスペルシンプルを意味し、単語レコードので、単語の本を使用しました。また、多くの外国の本は、アルゴリズムは、問題に対処する単語をマークするためにこの本を使用するので、私がフォローアップするためにここにいますもあります。あなたはそれをよく理解して感じるのでもちろん、あなたはまた、ワードマークを使用することができます。以下は、本の配列にする必要がある[1]〜予約[9]は、カードなしでデスクトップの初めから、0に初期化されます。
for(i=1;i<=9;i++)
book[i]=0;
カード2用のテーブル上のカードの顔の増加は、それが予約する必要があるかどう次に、[2]符号の顔を示し、1に設定されている2が既に持っているポーカーテーブルです。2枚のカードが奪われているカードの表面であれば後もちろん、タイムリーブックの必要性は、[2]テーブルの上に何のカードがないことを示す、0にリセットされ、ブランドの2のために直面しなければなりません。表は同じカードと顔のカードがプレイしているかどうかをその結果、見つける、あなたはあなたができる場合は、テーブル上のが、唯一の裁判官によってすべてのカードを列挙リサイクルする必要はありません。これはそれを行うための最初の方法の第1章のバケットソートのようなビットではないでしょうか?従います。
t=q1.data[q1.head]; //小哼先亮出一张牌
if(book[t]==0) // 表明桌上没有牌面为t的牌
{
//小哼此轮没有赢牌
q1.head++; //小哼已经打出一张牌,所以要把打出的牌出队
s.top++;
s.data[s.top]=t; //再把打出的牌放到桌上,即入栈
book[t]=1; //标记桌上现在已经有牌面为t的牌
}
コード:
完全なコードは次のとおりです。
#include <stdio.h>
struct queue
{
int data[1000];
int head;
int tail;
};
struct stack
{
int data[10];
int top;
};
int main()
{
struct queue q1,q2;
struct stack s;
int book[10];
int i,t;
//初始化队列
q1.head=1; q1.tail=1;
q2.head=1; q2.tail=1;
//初始化栈
s.top=0;
//初始化用来标记的数组,用来标记哪些牌已经在桌上
for(i=1;i<=9;i++)
book[i]=0;
//依次向队列插入6个数
//小哼手上的6张牌
for(i=1;i<=6;i++)
{
scanf("%d",&q1.data[q1.tail]);
q1.tail++;
}
//小哈手上的6张牌
for(i=1;i<=6;i++)
{
scanf("%d",&q2.data[q2.tail]);
q2.tail++;
}
while(q1.head<q1.tail && q2.head<q2.tail ) //当队列不为空的时候执行循环
{
t=q1.data[q1.head];//小哼出一张牌
//判断小哼当前打出的牌是否能赢牌
if(book[t]==0) //表明桌上没有牌面为t的牌
{
//小哼此轮没有赢牌
q1.head++; //小哼已经打出一张牌,所以要把打出的牌出队
s.top++;
s.data[s.top]=t; //再把打出的牌放到桌上,即入栈
book[t]=1; //标记桌上现在已经有牌面为t的牌
}
else
{
//小哼此轮可以赢牌
q1.head++;//小哼已经打出一张牌,所以要把打出的牌出队
q1.data[q1.tail]=t;//紧接着把打出的牌放到手中牌的末尾
q1.tail++;
while(s.data[s.top]!=t) //把桌上可以赢得的牌依次放到手中牌的末尾
{
book[s.data[s.top]]=0;//取消标记
q1.data[q1.tail]=s.data[s.top];//依次放入队尾
q1.tail++;
s.top--; //栈中少了一张牌,所以栈顶要减1
}
}
t=q2.data[q2.head]; //小哈出一张牌
//判断小哈当前打出的牌是否能赢牌
if(book[t]==0) //表明桌上没有牌面为t的牌
{
//小哈此轮没有赢牌
q2.head++; //小哈已经打出一张牌,所以要把打出的牌出队
s.top++;
s.data[s.top]=t; //再把打出的牌放到桌上,即入栈
book[t]=1; //标记桌上现在已经有牌面为t的牌
}
else
{
//小哈此轮可以赢牌
q2.head++;//小哈已经打出一张牌,所以要把打出的牌出队
q2.data[q2.tail]=t;//紧接着把打出的牌放到手中牌的末尾
q2.tail++;
while(s.data[s.top]!=t) //把桌上可以赢得的牌依次放到手中牌的末尾
{
book[s.data[s.top]]=0;//取消标记
q2.data[q2.tail]=s.data[s.top];//依次放入队尾
q2.tail++;
s.top--;
}
}
}
if(q2.head==q2.tail)
{
printf("小哼win\n");
printf("小哼当前手中的牌是");
for(i=q1.head;i<=q1.tail-1;i++)
printf(" %d",q1.data[i]);
if(s.top>0) //如果桌上有牌则依次输出桌上的牌
{
printf("\n桌上的牌是");
for(i=1;i<=s.top;i++)
printf(" %d",s.data[i]);
}
else
printf("\n桌上已经没有牌了");
}
else
{
printf("小哈win\n");
printf("小哈当前手中的牌是");
for(i=q2.head;i<=q2.tail-1;i++)
printf(" %d",q2.data[i]);
if(s.top>0) //如果桌上有牌则依次输出桌上的牌
{
printf("\n桌上的牌是");
for(i=1;i<=s.top;i++)
printf(" %d",s.data[i]);
}
else
printf("\n桌上已经没有牌了");
}
getchar();getchar();
return 0;
}
リスト
店舗波の多数において、我々は、通常、アレイを使用し、アレイは、非常に柔軟時には、次の例のようではなかったです。大規模なソート番号2358910182632に小さな一連のがありました。この番号にはまだ昇順を満たすための新しいシーケンスが得られるように、文字列6を挿入するようになりまし必要があります。私たちは、この動作を実現するために、配列を使用する場合は、8,8は1ターンに戻って移動して戻ってカウントする必要があります。
リストには、はるかに高速になる場合、このような操作は明らかに、時間を無駄にしました。だから、リンクリスト、それは何ですか?下記を参照してください。
まず、保存する方法である必要があり、リンクされたリスト内のすべてのノードを見てください。
各ノードは、2つの部分から構成されています。特定の値を格納するための部分を残し、あなたは整数変数を使用することができる。アドレスの右下部分(また、後続ポインタと呼ぶ)のポインタを使用して実装することができるノードに格納される必要があります。次のようにここでは、このノードを格納するために使用されるタイプの構造を定義します。
struct node
{
int data;
struct node *next;
};
上記のコードは、我々はノードと呼ばれる構造のタイプ。このタイプの構造は、2つの部材を有していると定義します。データの最初のメンバーは、特定の値を格納するための、整数であり、第2の部材は次のノードのメモリアドレスへのポインタです。*次のノードタイプは構造体のノードであるので、このポインタのタイプはタイプstructノードのポインタでなければなりませんので。
リンクリストを作成する方法は?まず、リストの先頭に先頭ポインタのヘッド・ポイントを必要としています。リストは、ヘッド・ポインタのヘッドを確立していないとき(ノードがnullにすることを理解することができるように)空です。
struct node *head;
head = NULL;//头指针初始为空
今度は、最初のノードを作成してみましょう、と一時的なポインタpのノードを指します。
struct node *p;
//动态申请一个空间,用来存放一个结点,并用临时指针p指向这个结点
p=(struct node *)malloc(sizeof(struct node));
次に、それぞれ、新たに作成されたノードの一部を左右半分を設定します。
scanf("%d",&a);
p->data=a;//将数据存储到当前结点的data域中
p->next=NULL;//设置当前结点的后继指针指向空,也就是当前结点的下一个结点为空
一時的なポインタpは、新しく作成されたノードを指すようになりますので、最後に、少し後に、カーソルqはまた、現在のノードを指して置きます。
Q = P; //ポインタは、現在のノードqを指し
完全なコード:
#include <stdio.h>
#include <stdlib.h>
//这里创建一个结构体用来表示链表的结点类型
struct node
{
int data;
struct node *next;
};
int main()
{
struct node *head,*p,*q,*t;
int i,n,a;
scanf("%d",&n);
head = NULL;//头指针初始为空
for(i=1;i<=n;i++)//循环读入n个数
{
scanf("%d",&a);
//动态申请一个空间,用来存放一个结点,并用临时指针p指向这个结点
p=(struct node *)malloc(sizeof(struct node));
p->data=a;//将数据存储到当前结点的data域中
p->next=NULL;//设置当前结点的后继指针指向空,也就是当前结点的下一个结点为空
if(head==NULL)
head=p;//如果这是第一个创建的结点,则将头指针指向这个结点
else
q->next=p;//如果不是第一个创建的结点,则将上一个结点的后继指针指向当前结点
q=p;//指针q也指向当前结点
}
//输出链表中的所有数
t=head;
while(t!=NULL)
{
printf("%d ",t->data);
t=t->next;//继续下一个结点
}
getchar();getchar();
return 0;
}
なお、このです:上記のコードはエラーなしものの、動的なアプリケーションに領域を解放しませんが、これは
安全ではない、興味を持って友人がfreeコマンドを見に行くことができます。
アナログ一覧
コードは以下の通りであります:
#include <stdio.h>
int main()
{
int data[101],right[101];
int i,n,t,len;
//读入已有的数
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&data[i]);
len=n;
//初始化数组right
for(i=1;i<=n;i++)
{
if(i!=n)
right[i]=i+1;
else
right[i]=0;
}
//直接在数组data的末尾增加一个数
len++;
scanf("%d",&data[len]);
//从链表的头部开始遍历
t=1;
while(t!=0)
{
if(data[right[t]]>data[len])//如果当前结点下一个结点的值大于待插入数,将数插入到中间
{
right[len]=right[t];//新插入数的下一个结点标号等于当前结点的下一个结点编号
right[t]=len;//当前结点的下一个结点编号就是新插入数的编号
break;//插入完成跳出循环
}
t=right[t];
}
//输出链表中所有的数
t=1;
while(t!=0)
{
printf("%d ",data[t]);
t=right[t];
getchar();
getchar();
return 0;
}
}
リストはまた、アナログおよび循環リスト、二重リンクリストを使用して実施することができます。