程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 避免回溯方法,回溯方法

避免回溯方法,回溯方法

編輯:C#入門知識

避免回溯方法,回溯方法


    半月沒來博客園,換了一份新工作,開始繁瑣的事情一大堆,實在沒閒工夫寫什麼了,這篇大概是我半年前寫在別處的,不過我覺得是不錯的方法,至少我個人這麼覺得。回溯法是不可控的,有時候會超出我們意料之外產生不妙的結果,最常見的也就是內存洩漏。一下是原文照搬過來的,不過是我自己寫的,我也不加出處了。(如果是引用別人的我會加上出處,咱不埋沒別人的智慧。)


 

  回溯方法是很容易想到,又不容易想到的,往往,我們思維更容易進入的是回溯法。但是回溯法有著它的弊端,非常明顯的弊端是作用域內產生的變量和引用在回溯法調用未完成時,不能釋放(對於大部分編輯器來說,排除有著優化能力的編輯器)。如果我們在某一方法中使用極多的回溯調用,在方法中不能及時的對方法作用域內的變量和引用釋放,最終會造成內存不足和cpu的計算負荷增大(內存機制中可以將過剩的數據轉存到虛擬內存、硬盤,這個就不說了)。使用棧(隊)式的循環,可以輕易避免回溯法,而且棧(隊)式的數據再使用之後可以很方便的拋出移除。某些時候就是這樣,一個小小的改動,可以讓一個程序在某種特定的環境中起死回生。(之前做過一個數獨運算器的算法,後來的優化改進就是為了避免回溯)

 

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.IO; 6 7 namespace 避免回溯方法 8 { 9 class Program 10 { 11 static void Main(string[] args) 12 { 13 string path = AppDomain.CurrentDomain.BaseDirectory; 14 15 List<string> fileList1 = new List<string>(); 16 FunctionHuishuo(path, ref fileList1); 17 18 List<string> fileList2 = new List<string>(); 19 FunctionQueue(path, ref fileList2); 20 21 List<string> fileList3 = new List<string>(); 22 FunctionStack(path, ref fileList3); 23 } 24 25 /// <summary> 26 /// 回溯法 27 /// </summary> 28 /// <param name="path"></param> 29 /// <param name="fileList"></param> 30 private static void FunctionHuishuo(string path, ref List<string> fileList) 31 { 32 if (true) 33 { 34 string[] files = null; 35 try 36 { 37 files = Directory.GetFiles(path); 38 } 39 catch { } 40 41 if (files != null && files.Length > 0) 42 { 43 fileList.AddRange(files); 44 } 45 } 46 47 if (true) 48 { 49 string[] folders = null; 50 try 51 { 52 folders = Directory.GetDirectories(path); 53 } 54 catch { } 55 56 if (folders != null && folders.Length > 0) 57 { 58 foreach (string folder in folders) 59 { 60 FunctionHuishuo(folder, ref fileList); 61 } 62 } 63 } 64 } 65 66 /// <summary> 67 /// 堆棧法 68 /// </summary> 69 /// <param name="path"></param> 70 private static void FunctionStack(string path, ref List<string> fileList) 71 { 72 Stack<string> stack = new Stack<string>(); 73 stack.Push(path); 74 75 while (stack.Count > 0) 76 { 77 string dir = stack.Pop(); 78 79 string[] files = null; 80 try 81 { 82 files = Directory.GetFiles(dir); 83 } 84 catch { } 85 86 if (files != null && files.Length > 0) 87 { 88 fileList.AddRange(files); 89 } 90 91 string[] folders = null; 92 try 93 { 94 folders = Directory.GetDirectories(dir); 95 } 96 catch { } 97 98 if (folders != null && folders.Length > 0) 99 { 100 foreach (string folder in folders) 101 { 102 stack.Push(folder); 103 } 104 } 105 } 106 } 107 108 /// <summary> 109 /// 隊列法 110 /// </summary> 111 /// <param name="path"></param> 112 private static void FunctionQueue(string path, ref List<string> fileList) 113 { 114 Queue<string> queue = new Queue<string>(); 115 116 queue.Enqueue(path); 117 118 while (queue.Count > 0) 119 { 120 string dir = queue.Dequeue(); 121 122 string[] files = null; 123 try 124 { 125 files = Directory.GetFiles(dir); 126 } 127 catch { } 128 129 if (files != null && files.Length > 0) 130 { 131 fileList.AddRange(files); 132 } 133 134 string[] folders = null; 135 try 136 { 137 folders = Directory.GetDirectories(dir); 138 } 139 catch { } 140 141 if (folders != null && folders.Length > 0) 142 { 143 foreach (string folder in folders) 144 { 145 queue.Enqueue(folder); 146 } 147 } 148 } 149 } 150 } 151 } 以碼當先


請仔細對比下三種循環結構的寫法,特別注意下裡面有用到  if(true){...}   ,這種方式在某些編輯環境中可以產生非常美妙的效果,你造嗎?

 

好了,就這麼多吧,實在沒時間寫新東西了。以後出貼應該很慢了,不過會出點服務器集群方面的帖子,這些帖子現存的已經很多,但是大部分都是視圖文字說明,對於新手來說很難掌握,我自己曾經摸索的時候,可是煞費苦心啊。它需要的條件非常苛刻,需要大量服務器、高並發訪問、以及核心數據庫和分化數據庫策略等等,如果用一帖把它給解釋清楚,我感覺就是天方夜譚,它完全可以出成一本書,所以在一帖中講解集群使用圖文方式是最好的方式,比較全面概括,所以我沒怪過前輩們寫集群方面的知識寫的太籠統,完全不明所以。前輩們寫這麼高明的帖子是給有心人看的,他想把他的思想教給我們;我寫帖子完全是給屌絲看的,做個知識的入門引導吧,呵呵。(預先掌握golang,erlang編程)


回溯法解決實際問題

已經過tc2.0調試,可實現題目要求。
#include<stdio.h>
#include<dos.h>
int max=0; /*存放最大價值數*/
int a[21],r[21];
/*a[]用於存放每次生成的放置組合,r[]存放最大價值的存放組合*/
int vv[21];
struct s
{ int w,v,i;
} x[21]; /*存放物品價值、標號與重量的結構體*/
void solve(int n,int m,int *b,int *v,struct s *x);
void save(void);
int main()
{ int n,m,i;
printf("M=");
scanf("%d",&m);
do
{ printf("n=");
scanf("%d",&n);
if(n<1||n>20) printf("Data error.\n");
} while(n<1||n>20);
for(i=0;i<n;i++) /*輸入每個物品的信息*/
{ printf("w[%d]=",i+1);
scanf("%d",&(x[i].w));
printf("v[%d]=",i+1);
scanf("%d",&(x[i].v));
x[i].i=i+1;
}
system("cls"); /*清空屏幕*/
for(i=0;i<n;i++) /*顯示各物品信息*/
{ printf("w[%d]=%d ",i+1,x[i].w);
printf("v[%d]=%d\n",i+1,x[i].v);
}
printf("m=%d\n",m);
solve(n,m,a,vv,x); /*調用函數求解*/
printf("所存物品的編號\n");
for(i=0;r[i]>0;i++)
printf("%d ",r[i]);
printf("\n");
printf("總價值: %d\n",max);
getch();
}
void solve(int n,int m,int *b,int *v,struct s *x)
/*運用回溯法求解的函數*/
/*n表示還剩幾個物品,m表示剩余空間*/
{ int i,w,f=0;
/*f為標志變量,代表剩下的空間能否再放下物品,1為可以*/
for(i=0;i<n;i++) if(m>=x[i].w) f=1;
if(!f) { b[0]=-1;save();return; }
if(n==1)
{ b[0]=x[0].i;b[1]=-1;v[0]=x[0].v;save();return; }
for(i=0;i<n;i++)
{ if(m<x[i].w) cont......余下全文>>
 

系統講解回溯法

以前算法試驗做得
勉強看看吧

回溯的精髓在於不知道解決問題的確定方向,
就硬著頭皮往前走,可以走的地方都走,
到最後沒路可走到死路時,才往回退回上一個路口試探別的路

個人感覺有點像圖的深度遍歷
--------------------------------------------

//八皇後問題
//2008-04-23
//作者:leo

#include <iostream>
using namespace std;
#define N 8//皇後個數
int x[N+1]={0};//定義棋盤

bool place(int k)//判斷k位置擺放皇後是否合理
{
int i=1;
while(i<k)
{
if(x[i]==x[k]||(abs(x[i]-x[k])==abs(i-k)))return false;
i++;
}
return true;
}

void print()//打印結果
{
for(int i=1;i<N+1;i++)
cout<<x[i]<<" ";
cout<<endl;
}

void nqueen(int k)//
{
int count=0;//解決方案數
while(k>=1)
{
x[k]++;
while(x[k]<=N&&!place(k))//從第一個位置開始試擺第k個皇後
{
x[k]++;
}
if(x[k]<=N)//第k個皇後安全時在棋盤內
{
if(k==N)//已經是第最後一個皇後則得到一個解決方案
{
count++;
cout<<count<<endl;
print();
}
else k++;//繼續處理下一個皇後

}
else x[k--]=0;//第k個皇後安全時不在棋盤內,則回溯
}
}

void main()
{
nqueen(1);
}...余下全文>>
 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved